Is it possible to 'pass' a parameter through a function without copying?
Let's make up an example:
std::string check(std::string in, int &maxLen)
{
maxLen = std::max(maxLen, in.length());
return in;
}
//main:
int maxCnt = 0;
std::cout
<< check("test, ", maxCnt)
<< check("two tests, ", maxCnt)
<< check("three tests, ", maxCnt)
<< maxCnt;
// would output: "test, two tests, three tests, 13"
My c++ compiler foo isn't good enough to say if this may already be optimized away.
What would the signature of check(...)
have to look like so that a temporary argument would never be copied?
My first guess was:
std::string && check(std::string &&in, int &maxLen)
If this is correct, what would the implementation look like?
Remarks:
std::string
is a placeholder, it should work with any complex typeIf you want to avoid any copy of the input string, you should write your function as:
std::string const& check(std::string const& input, int& maxLen) {
maxLen = std::max(maxLen, input.size());
return in;
}
The argument passed by const
reference is pretty obvious. Why the return though? Because RVO cannot elide the copy here. RVO happens when you are building an object (an lvalue) in your function and return it (that includes lvalue arguments as well). The compiler elides the copy by automatically building the object where it is supposed to go. Here, if you return an lvalue (either std::string const
or std::string
), the compiler will see you want to store the return value somewhere and will have to perform a copy from your reference to that destination. By using a std::string const&
, you will avoid that because the operator <<
from std::basic_ostream
handles const references as well.
To sum up, with the check()
definition above:
int max(0);
std::string toto("Toto");
std::string lvalue = check(toto, max); // copy
std::string const& const_ref = check(toto, max); // no-copy
std::cout << check(toto, max) << std::endl; // no-copy
The overload resolution in the last call will chose:
template <class CharT, class Traits, class Allocator>
std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& os,
const std::basic_string<CharT, Traits, Allocator>& str);
// ^^^^^ const ref here for the string argument