Search code examples
c++c++11movenrvo

c++ - NRVO and move


I have read a few posts about move functions (http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html for example), and I wanted to observe move operators in action. So I tried the following code:

#include <vector>
#include <cassert>
#include <functional>
#include <algorithm>
#include <iostream>
using namespace std;

vector<double> operator+(const vector<double>& a, const vector<double>& b){
  assert(a.size()==b.size());
  vector<double> result(a.size(),0);
    transform (a.begin(), a.end(), b.begin(), result.begin(), std::plus<double>());
  cout<<&result<<endl;
  return result;
}

int main(int argc, char const *argv[]) {
  vector<double> a,b;
  for (int i=0;i<10;i++){
    a.push_back(i);
    b.push_back(1);
  }
  std::vector<double> c=a+b;
  cout<<&c<<endl;
  return 0;
}

I was expecting to obtain the same address for the local variable result and c since move operators are implemented for vector. And I obtained exactly that, but with and without the flag -std=c++11. That is when I learned about NRVO (c++11 Return value optimization or move?), so I disabled it with the flag -fno-elide-constructors and now the address is different, even with the flag -std=c++11. Is there an issue with my code or did I understand something wrong about move operators ?

From what I understood, returning by value should be enough for the move operator to kick in (C++11 rvalues and move semantics confusion (return statement)).

PS: I tried with GCC 6.3.0_1 and Apple LLVM version 8.1.0 .

EDIT

As pointed out, I should have checked result.data() instead of &result (see below). But in that case, I always found the same address, even without std=c++11 and with -fno-elide-constructors. See accepted answer and its comment section.


Solution

  • Think of a move as an optimized copy. It is still a copy, so it is still a different vector but it has "moved" the underlying data from one vector to the other. You can see that by comparing the address of the data:

    cout<<result.data()<<endl;
    

    and

    cout<<c.data()<<endl;
    

    Copy elision on the other hand eliminates the copy entirely.