C++: should I explicitly use std::move() in a return statement to force a move? [duplicate]
Asked Answered
L

1

2

EDIT: it is NOT a duplicate because this question asks about a compiler's decision in O0.

It is said here that Name Return Value Optimization (NRVO) is an optimization many compiler support. But is it a must or just a nice-to-have optimization?

My situation is, I want to compile with -O0 (i.e. no optimization), for convenience of debugging, but I also want NRVO to be enabled for return statements that return objects (say, a vector). If NRVO is not a must, the compiler probably won't do it in -O0 mode. In this case, should I prefer this code:

std::vector<int> foo() {
    std::vector<int> v(100000,1); // an object that is really big..
    return std::move(v);  // explicitly move
}

over this below?

std::vector<int> foo() {
    std::vector<int> v(100000,1);
    return v;    // copy or move?
}

EDIT: the compiler I am using is GCC6, but I want the code to be compiler-independent.

Lechner answered 14/8, 2017 at 18:37 Comment(7)
Whether the return value gets copied or moved is determined by the function's return type, and its calling context. Nothing that occurs inside the function will have any bearing on that.Carlsbad
See https://mcmap.net/q/16167/-c-11-rvalues-and-move-semantics-with-return-statementInsolvable
The move is superfluous as the value is already an rvalue (xvalue), and it prohibits copy-elison. So it's just a pessimization overall. Also, don't optimize your unoptimized builds.Purism
Alternative duplicate: https://mcmap.net/q/76912/-c-11-return-value-optimization-or-move-duplicate/1896169Shoreless
@Shoreless i know this post but it didn't say if the optimization is enabled in O0.Lechner
@HowardHinnant thanks but it does not mention whether it is enabled in O0.Lechner
Your only concern should be correctness and selection of the optimal algorithm. Code optimisation is the compiler's concern. Almost always prefer returning by value over returning by r-value reference.Burse
C
6

You should prefer

std::vector<int> foo() {
    std::vector<int> v(100000,1);
    return v;    // move or NRVO
}

over

std::vector<int> foo() {
    std::vector<int> v(100000,1);
    return std::move(v);    // move
}

The second snippet prevent NRVO, and in worst case both would move construct.

Churning answered 14/8, 2017 at 18:50 Comment(10)
why is move construction bad? I thought copy construction is unnecessary and therefore is bad.Lechner
In first snippet, you have move constructor or even better NRVO (and in C++17 NRVO guaranty :-) ). In the second snippet, the move call prevent NRVO, so you only have move construct, that is not that bad, but we have better or equal in first snippet with a shorter code.Churning
Not all moves are free. Some moves require additional work to ensure the moved from object is in a valid state. unordered_map for instance, will allocate buckets for a moved from object.Conceit
@Chad: Only in some implementations. libc++ does not. I suspect libstdc++ does not. howardhinnant.github.io/container_summary.htmlInsolvable
@Churning So..sorry for my confusion.. it seems that NRVO and move are not the same thing. Are they?Lechner
@Churning From your comment's wording, is it correct that copy constructor won't be called in the first snippet no matter what?Lechner
(N)RVO and moving are not the same thing. RVO existed prior to C++11 - it's just a permitted optimization compilers can take. And correct, the copy constructor won't ever be called - at that point v is an rvalue (an xvalue, to be precise) so the constructor that accepts an rvalue (the move constructor) is a better match then the one that doesn't (the copy constructor).Purism
@HowardHinnant You're right, but I think in general there is no guarantee that a move is trivial for all data types.Conceit
not compiling in C++11 when copy constructor is a deleted function. Hence, IMHO is not "force" movingPate
@HAL9000: Work as expected here (nrvo) and here (move).Churning

© 2022 - 2024 — McMap. All rights reserved.