1

我已经阅读了一些关于移动函数的帖子(例如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. 我得到了确切的结果,但是有和没有 flag -std=c++11。那是我了解 NRVO(c++11 返回值优化还是移动?)的时候,所以我用标志禁用了它,-fno-elide-constructors现在地址不同了,即使有标志也是如此-std=c++11。我的代码有问题还是我对移动运算符有什么误解?

据我了解,按值返回应该足以让移动运算符发挥作用(C++11 右值和移动语义混淆(返回语句))。

PS:我尝试使用 GCC 6.3.0_1 和 Apple LLVM 版本 8.1.0 。

编辑

正如所指出的,我应该检查result.data()而不是&result(见下文)。但在那种情况下,我总是找到相同的地址,即使没有std=c++11和有-fno-elide-constructors. 请参阅接受的答案及其评论部分。

4

2 回答 2

3

移动构造函数通过窃取旧对象的资源来构造一个新对象。它根本不合并临时对象:如果没有省略构造,您仍然有两个对象。

于 2017-06-06T09:10:34.727 回答
2

将移动视为优化的副本。它仍然是一个副本,因此它仍然是一个不同的向量,但它已将基础数据从一个向量“移动”到另一个向量。通过比较数据的地址可以看出:

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

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

另一方面,复制省略完全消除了副本。

于 2017-06-06T09:12:50.297 回答