Reputation: 3388
I have a function foo:
std::vector<T> foo() {
std::vector<T> result;
// populate result
{
/*
for loop with result.push_back().
ignore real code.
*/
}
//
return result; <-- note there without std::move
}
Will it do extra copy if I assign like the following?
const auto v = foo(); <-- will it move the vector by default?
const auto &v = foo(); <-- same question as above, assuming T is movable
I am in particular interested in the second case as for the first case it's very likely the compiler knows to move the result from foo() to v.
const auto &v = foo();
For this case, the foo() function creates a temp result. Now as v is a reference, it can't move result to v. Thus it needs to create a new copy. Is my understanding right?
Upvotes: 3
Views: 122
Reputation: 870
The compilers are permitted to any and all code transformations that do not change the observable behavior of the program, by applying the as-if rule.
However, copy_elision is an exception from the as-if rule: the compiler may remove calls to move- and copy-constructors and the matching calls to the destructors of temporary objects even if those calls have observable side effects. To witness these side effects, you have to use -fno-elide-constructors
option while compiling.
From the copy_elision page, we should look at the clause:
In a return statement, when the operand is the name of a non-volatile object with automatic storage duration, which isn't a function parameter or a catch clause parameter, and which is of the same class type (ignoring cv-qualification) as the function return type. This variant of copy elision is known as NRVO, "named return value optimization".
When the compiler sees the below structure, it knows it is a candidate for NRVO.
T FunctionName ( ... )
{
T a;
...
return a;
}
Which matches the code structure of your problem.
std::vector<T> foo() {
std::vector<T> result;
// populate result
{
/*
for loop with result.push_back().
ignore real code.
*/
}
return result;
}
Case 1 -
const auto v = foo(); <-- will it move the vector by default?
What you are witnessing is not move-semantics, it is just NRVO.
So the question doesn't have any relevance here.
Case 2 -
const auto &v = foo(); <-- same question as above, assuming T is movable
It doesn't matter if T
is movable. There is no move
happening here.
The concept that is taking place is const &
can bind to a temporary.
We would achieve the same result in pre-C++11 compiler as well, which didn't have move-semantics support.
Upvotes: 3
Reputation: 3388
For both cases, it seems there's no extra copy, seen from this link
Upvotes: 0