我有以下代码段。有谁知道为什么在主函数中没有为所有情况调用此移动构造函数?为什么要编译呢?赋值运算符是私有的吗?这里有链接:http://ideone.com/bZPnyY
#include <iostream>
#include <vector>
class A{
public:
A(int i){
std::cout << "Constructor "<< i <<std::endl;
for(int l = 0; l<i;l++){
vec.push_back(l);
}
};
A(A && ref): vec(std::move(ref.vec))
{
std::cout << "Move constructor"<<std::endl;
}
A & operator=(A && ref){
if(this != &ref){
vec = std::move(ref.vec);
}
std::cout << "Move assignment"<<std::endl;
return *this;
}
std::vector<int> vec;
private:
A(const A & ref);
A(A & ref);
A & operator=(A & ref);
};
A makeA(){
A a(3);
return a;
}
int main(){
A b1(makeA()) ;
A b2 = makeA();
A b3 = A(3);
A b4(A(3));
std::cout << b4.vec[2] << std::endl;
};
输出:
构造函数3
构造函数3
构造函数3
构造函数3
2
回复的一些补充: 当我添加
std::pair<int,A> a(3,A(3));
然后调用移动构造函数(所以希望没有NRVO)
答案 0 :(得分:6)
您所看到的被称为 copy elision ,并记录在12.8.31中。
A makeA(){
A a(3);
return a;
}
A b1(makeA()) ;
A b2 = makeA();
此处,a
中的makeA
局部变量直接放在makeA
的返回值中,而makeA
的临时返回值直接放在b1
中。 b2
和A b3 = A(3);
A b4(A(3));
的存储空间。 (连续两个副本)
A(3)
使用b3
创建的临时文件直接在b4
和b1
中构建。 (一份副本)
当满足某些条件时,允许实现省略类的复制/移动构造 即使为复制/移动操作选择的构造函数和/或对象的析构函数也是如此 有副作用。在这种情况下,实现会处理省略的复制/移动的源和目标 操作只是两种不同的方式来引用同一个对象,以及对该对象的破坏 发生在两个对象在没有优化的情况下被破坏的时间的晚期.122 复制/移动操作的省略,称为复制省略,在以下情况下是允许的(其中 可以合并以消除多个副本):
这是b2
和b1
案例的第一部分:
- 在具有类返回类型的函数的return语句中,当表达式是a的名称时 非易失性自动对象(函数或catch子句参数除外)具有相同的cv- 作为函数返回类型的非限定类型,可以通过构造省略复制/移动操作 自动对象直接进入函数的返回值
这是b2
和b3
案例的第二部分,以及b4
和{{1}}案例的整个部分:
- 当复制/移动尚未绑定到引用(12.2)的临时类对象时 对于具有相同cv-unqualified类型的类对象,可以省略复制/移动操作 将临时对象直接构造到省略的copy / move
的目标中
还有另外两个复制省略允许的情况与抛出和捕获异常有关。
答案 1 :(得分:1)
复制赋值运算符甚至无处可去,也不会混淆=
令牌与赋值的混淆(例如,b1 = b2;
)。
A b1(makeA()) ; // direct initialization
A b2 = makeA(); // copy-initialization
A b3 = A(3); // copy-initialization
A b4(A(3)); // direct initialization
虽然复制初始化要求良好,但要求可以访问复制或移动构造函数,编译器可以自由地删除它并直接初始化对象。关于哪个构造函数符合每个构造函数的细微差别,请阅读有关此here的更多信息。
如果您正在使用GCC,请尝试使用-fno-elide-constructors
进行编译并查看差异。