C++ - NRVO и переезд
Я прочитал несколько постов о функциях перемещения (например, http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html) и хотел наблюдать за ходом операторов в действии. Поэтому я попробовал следующий код:
#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;
}
Я ожидал получить тот же адрес для локальной переменной result
а также c
так как операторы перемещения реализованы для vector
, И я получил именно это, но с и без флага -std=c++11
, Именно тогда я узнал о NRVO ( оптимизация возвращаемого значения C++11 или перемещение?), Поэтому я отключил его с флагом -fno-elide-constructors
и теперь адрес другой, даже с флагом -std=c++11
, Есть ли проблема с моим кодом или я что-то не так понял в операторах перемещения?
Из того, что я понял, возврата по значению должно быть достаточно для включения оператора перемещения (значения C++11 и путаница в семантике перемещения (оператор return)).
PS: я пробовал с GCC 6.3.0_1 и Apple LLVM версии 8.1.0 .
РЕДАКТИРОВАТЬ
Как указано, я должен был проверить result.data()
вместо &result
(увидеть ниже). Но в этом случае я всегда находил один и тот же адрес, даже без std=c++11
и с -fno-elide-constructors
, Смотрите принятый ответ и его раздел комментариев.
2 ответа
Думайте о движении как о оптимизированной копии. Это все еще копия, поэтому это все еще другой вектор, но он "переместил" лежащие в основе данные из одного вектора в другой. Вы можете увидеть это, сравнив адрес данных:
cout<<result.data()<<endl;
а также
cout<<c.data()<<endl;
Копия elision, с другой стороны, полностью исключает копию.
Конструктор перемещения создает новый объект путем кражи ресурсов старого. Он вообще не объединяет временные блоки: если конструкция не исключена, у вас все еще есть два объекта.