c++ - NRVO 和移动
c++ - NRVO and move
我已经阅读了一些关于移动函数的帖子(例如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 Return value optimization or move?) 的时候,所以我用标志 -fno-elide-constructors
禁用了它,现在地址不同了,即使标志 -std=c++11
也是如此。我的代码有问题还是我对移动运算符的理解有误?
据我了解,按值返回应该足以让移动运算符启动 (C++11 rvalues and move semantics confusion (return statement))。
PS:我尝试使用 GCC 6.3。0_1 和 Apple LLVM 版本 8.1.0。
编辑
正如所指出的,我应该检查 result.data()
而不是 &result
(见下文)。但在那种情况下,我总是找到相同的地址,即使没有 std=c++11
和 -fno-elide-constructors
。请参阅已接受的答案及其评论部分。
移动构造函数通过窃取旧对象的资源来构造一个新对象。它根本不合并临时对象:如果没有省略构造,您仍然有两个对象。
将移动视为优化的副本。它仍然是一个副本,所以它仍然是一个不同的向量,但它具有从一个向量到另一个向量的基础数据 "moved"。对比数据的地址可以看出:
cout<<result.data()<<endl;
和
cout<<c.data()<<endl;
另一方面,复制省略完全消除了复制。
我已经阅读了一些关于移动函数的帖子(例如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 Return value optimization or move?) 的时候,所以我用标志 -fno-elide-constructors
禁用了它,现在地址不同了,即使标志 -std=c++11
也是如此。我的代码有问题还是我对移动运算符的理解有误?
据我了解,按值返回应该足以让移动运算符启动 (C++11 rvalues and move semantics confusion (return statement))。
PS:我尝试使用 GCC 6.3。0_1 和 Apple LLVM 版本 8.1.0。
编辑
正如所指出的,我应该检查 result.data()
而不是 &result
(见下文)。但在那种情况下,我总是找到相同的地址,即使没有 std=c++11
和 -fno-elide-constructors
。请参阅已接受的答案及其评论部分。
移动构造函数通过窃取旧对象的资源来构造一个新对象。它根本不合并临时对象:如果没有省略构造,您仍然有两个对象。
将移动视为优化的副本。它仍然是一个副本,所以它仍然是一个不同的向量,但它具有从一个向量到另一个向量的基础数据 "moved"。对比数据的地址可以看出:
cout<<result.data()<<endl;
和
cout<<c.data()<<endl;
另一方面,复制省略完全消除了复制。