30

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?

Felix Glas
  • 15,065
  • 7
  • 53
  • 82
Koban
  • 463
  • 1
  • 6
  • 12

3 Answers3

37

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:

Felix Glas
  • 15,065
  • 7
  • 53
  • 82
  • 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 RVO – HAL9000 Jul 26 '19 at 16:14
  • 1
    @HAL9000 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 :) – Felix Glas Jul 29 '19 at 15:25
  • @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. – HAL9000 Jul 29 '19 at 15:34
  • @HAL9000 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. – Felix Glas Jul 30 '19 at 12:44
2

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

Nick Brown
  • 120
  • 6
Attila
  • 1,445
  • 1
  • 11
  • 21
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

knst
  • 523
  • 2
  • 16
  • 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. – Angew is no longer proud of SO May 19 '17 at 09:24