【发布时间】:2014-07-11 13:19:10
【问题描述】:
我正在测试一个移动构造函数并执行了以下操作:
#include <iostream>
#include <string>
using namespace std;
class X{
public:
int* p;
int size;
X(){}
X(int n) : size(n){
p = new int[n];
for(int i = 0; i < n; i++)
p[i] = i;
cout << "Constructor\n";
}
~X(){
delete[] p;
}
X(const X& r){
cout << "Copy\n";
}
X(X&& r){
p = r.p;
size = r.size;
r.p = NULL;
r.size = 0;
cout << "Move\n";
}
};
int main() {
X a(10); //constructor
X b(a); // copy
X c(X(3)); //constructor, move
return 0;
}
我在输出中的预期是在 cmets 中,但是在编译(VS 2012)时没有调用移动构造函数?!但是,如果我向构造函数添加额外的参数:
string name;
X(int n, string _name) : size(n), name(_name){
p = new int[n];
for(int i = 0; i < n; i++)
p[i] = i;
cout << "Constructor\n";
}
然后
X a(10, "a"); //constructor
X b(a); // copy
X c(X(3, "pom")); //constructor, move
我得到了预期的结果...我真的不明白为什么。
编辑:现在在 GCC 4.7.2 上进行了测试,在这两种情况下它都不会调用 Move 构造函数,但 C++ Builder XE5 编译器在这两种情况下都会调用 Move 构造函数。然而,VS 只在第二种情况下调用它(当使用额外的构造函数参数时)。很有趣...
【问题讨论】:
-
尝试使用
std::move。 -
我知道 std::move 但这并不能回答我的问题。
-
可能是编译器正在优化
X c(X(3))以将其转换为X c(3)。允许编译器这样做。它本质上是一个返回值优化:即使在移动语义之前,如果一个函数按值返回一些东西给分配给它的调用者,我相信编译器只允许在堆栈上的最终位置分配一次变量并“假装"返回它。 -
Ben 的假设是可靠的。最好在 X c(X(3)) 处设置断点并查看反汇编和/或尝试不进行任何优化。
-
“当满足某些条件时,允许实现省略类对象的复制/移动构造,即使对象的复制/移动构造函数和/或析构函数有副作用。” [如调试输出;-)] (12.8/31 复制和移动类对象)
标签: c++ c++11 constructor move-semantics