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.

Leedehai
  • 3,660
  • 3
  • 21
  • 44
  • 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. – Sam Varshavchik Aug 14 '17 at 18:40
  • See https://stackoverflow.com/a/4986802/576911 – Howard Hinnant Aug 14 '17 at 18:42
  • 1
    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. – GManNickG Aug 14 '17 at 18:44
  • Alternative duplicate: https://stackoverflow.com/q/17473753/1896169 – Justin Aug 14 '17 at 19:02
  • @Justin i know this post but it didn't say if the optimization is enabled in O0. – Leedehai Aug 14 '17 at 19:05
  • @HowardHinnant thanks but it does not mention whether it is enabled in O0. – Leedehai Aug 14 '17 at 19:09
  • 1
    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. – Richard Hodges Aug 14 '17 at 21:12

1 Answers1

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.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • why is move construction bad? I thought copy construction is unnecessary and therefore is bad. – Leedehai Aug 14 '17 at 19:07
  • 2
    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. – Jarod42 Aug 14 '17 at 19:14
  • 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. – Chad Aug 14 '17 at 19:37
  • @Chad: Only in some implementations. libc++ does not. I _suspect_ libstdc++ does not. http://howardhinnant.github.io/container_summary.html – Howard Hinnant Aug 14 '17 at 19:54
  • @Jarod42 So..sorry for my confusion.. it seems that NRVO and move are not the same thing. Are they? – Leedehai Aug 14 '17 at 20:44
  • @Jarod42 From your comment's wording, is it correct that copy constructor won't be called in the first snippet no matter what? – Leedehai Aug 14 '17 at 20:46
  • 1
    (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). – GManNickG Aug 14 '17 at 21:01
  • @HowardHinnant You're right, but I think in general there is no guarantee that a move is trivial for all data types. – Chad Aug 15 '17 at 13:08
  • not compiling in C++11 when copy constructor is a deleted function. Hence, IMHO is not "force" moving – HAL9000 Jul 26 '19 at 16:27
  • @HAL9000: Work as expected [here (nrvo)](http://coliru.stacked-crooked.com/a/f007ec041bd32456) and [here (move)](http://coliru.stacked-crooked.com/a/e28be1fe9b0b707f). – Jarod42 Jul 26 '19 at 19:58