Here is the article I am using as a reference, which was ultimately mentioned in this SO answer.
The author gives two examples:
Example 1:
std::vector<std::string>
sorted(std::vector<std::string> names)
{
std::sort(names);
return names;
}
// names is an lvalue; a copy is required so we don't modify names
std::vector<std::string> sorted_names1 = sorted( names );
// get_names() is an rvalue expression; we can omit the copy!
std::vector<std::string> sorted_names2 = sorted( get_names() );
Example 2:
std::vector<std::string>
sorted2(std::vector<std::string> const& names) // names passed by reference
{
std::vector<std::string> r(names); // and explicitly copied
std::sort(r);
return r;
}
Then saying:
Although sorted and sorted2 seem at first to be identical, there could be a huge performance difference if a compiler does copy elision. Even if the actual argument to sorted2 is an rvalue, the source of the copy, names, is an lvalue, so the copy can’t be optimized away. In a sense, copy elision is a victim of the separate compilation model: inside the body of sorted2, there’s no information about whether the actual argument to the function is an rvalue; outside, at the call site, there’s no indication that a copy of the argument will eventually be made.
My question is simple: Why cannot the compiler use copy elision in the second example, but it can in the first?
What about passing by value and reference differentiates them? names
is named in both instances, so I would assume we also create an lvalue in both instances.