Returning std::vector with std::move [duplicate]
Asked Answered
O

3

33

I have a very basic question: is it a good idea to return a std::vector<A> using std::move? For, example:

class A {};
std::vector<A> && func() {
    std::vector<A> v;
    /* fill v */
    return std::move(v);
}

Should I return std::map, std::list.. etc... in this way?

Optimism answered 19/5, 2017 at 9:5 Comment(5)
This won't compile.Lightfingered
Just return it by value.Broadleaved
std::vector<A> & v; ?? are you sure about that ?Cordellcorder
Returning by value should be considered preferable. You will get return value optimization, whereas with moving you will incur a move.Rutherfurd
I meant std::vector<A> v, without &Optimism
S
43

You declare a function to return by r-value reference - this should almost never be done (if you return the local object by reference, you will end up with a dangling reference). Instead declare the function to return by value. This way the caller's value will be move constructed by the r-value returned by the function. The returned value will also bind to any reference.

Secondly, no, you should not return using an explicit std::move as this will prevent the compiler to use RVO. There's no need as the compiler will automatically convert any l-value reference returned to an r-value reference if possible.

std::vector<A> func() {
    std::vector<A> v;
    /* fill v */
    return v; // 'v' is converted to r-value and return value is move constructed.
}

More info:

Scutellation answered 19/5, 2017 at 9:21 Comment(4)
This is not true until C++14. In C++11, when copy constructor is a deleted function, you need to explicitly std::move because RVO optimization is not guaranteed. For this reason, the compiler requires to have a copy constructor so that he will chose to copy when he decides he can't apply RVOGatewood
@Gatewood This answer is about std::vector, std::map, and std::list (see the question), which neither have their copy ctor deleted. There are of course other objects that need an explicit std::move, e.g. std::unique_ptr etc. Using an explicit move represent resource ownership transfer for cases where copying is disallowed by design, not optimization of return values. And btw, basically all compilers supported RVO during the C++11 era, even though it was not guaranteed by the standard :)Scutellation
@Snps I agree with the first part, I didn't pay enough attention to the question. For the RVO support, you didn't get the point: the language considers it an error when the copy constructor is a deleted function, because RVO support is not guaranteed, it doesn't matter if a compiler supports it.Gatewood
@Gatewood If the copy ctor was deleted by design and a user defined move ctor is present, then yes you would have to explicitly use std::move in C++11 if returning by value (if the move ctor is not user defined in this case, it would not be implicitly defined and you would get an error anyway). This all seems to be the exceptional case though.Scutellation
K
3

No, it's not. This will in fact prevent copy elision in some cases. There is even a warning in some compilers about it, called -Wpessimizing-move.

In agreement with other answers, just return it by value, changing the return type to simply be std::vector<A>, and the compiler will take care of calling the move constructor when needed.

You could take a look at this post I just found, which seems to explain it in much detail (although I haven't read it through myself): https://vmpstr.blogspot.hu/2015/12/redundant-stdmove.html

Karyogamy answered 19/5, 2017 at 9:24 Comment(3)
While correct on the pessimising move, this answer is dangerous because it fails to address the fact that the returned reference will be dangling.Vinificator
You don't think saying "just return it by value" kind of addresses this?Karyogamy
I consider it a tad too subtle: it can be interpreted as "just return the value without std::move" as well as "change the return type."Vinificator
S
1

Both gcc and clang compiler with enabled optimization generate same binary code for both case when you return local variable and when you write std::move(). Just return a value.

But using && and noexcept specifier is useful if you create moving constructor and moving operator= for your custom class

Sheila answered 19/5, 2017 at 9:13 Comment(1)
This has nothing to do with optimisations, really. The standard requires moving to be tried first in this case. Also, this answer is dangerous because it fails to address the fact that the returned reference will be dangling.Vinificator

© 2022 - 2024 — McMap. All rights reserved.