需要一些帮助来理解c++ 11移动构造函数
Need some help understanding C++11 Move Constructors
作为一个c++新手,我真的很难理解c++ 11中新的Move-Constructor,我希望有人能解释一下我偶然发现的一个具体情况。让我们看一下这个示例代码:
#include <iostream>
using namespace std;
class Model {
public:
int data;
Model(int data) : data(data) { cout << "Constructor" << endl; }
Model(Model&& model) { cout << "Move constructor" << endl; }
~Model() { cout << "Destructor" << endl; }
private:
Model(const Model& model);
const Model& operator=(const Model&);
};
Model createModel(int data) {
return Model(data);
}
int main(void) {
Model model = createModel(1);
cout << model.data << endl;
return 0;
}
所以我已经创建了一个createModel
函数,它应该返回一个模型作为一个临时右值,我想把它分配给一个左值。我不希望编译器创建Model
对象的副本,所以我将复制构造函数定义为私有,并使用赋值操作符进行相同的操作,以确保没有数据被复制。在这样做之后,代码不再正确编译,所以我添加了Move构造函数,现在它再次编译。但是当我运行程序时,我得到这样的输出:
Constructor
1
Destructor
所以Move构造函数没有被调用。我不明白为什么我必须指定移动构造函数才能在运行时根本不使用程序时编译程序。
是因为编译器(GCC 4.8.2)优化了Move构造函数吗?还是这里还表演了其他魔法?
那么有人能解释一下上面的代码到底发生了什么吗?代码做了我想要的,但我真的不明白为什么。
在您的程序中有两种可能发生的动作:
- 从函数到返回对象
- 从返回对象到
model
。
这两个动作都可以被编译器忽略,原因相同:
如果要将未绑定到引用(12.2)的临时类对象复制/移动到具有相同cv- undefined类型的类对象,则可以通过将临时对象直接构造为省略的copy/move
的目标来省略复制/移动操作。
在其他情况下会发生复制/移动省略(参见c++ 11中的§12.8/31)。注意,复制/移动省略是完全可选的——编译器不必这样做。
注意编译器被允许优化任何东西,只要它不改变你的程序的行为(在as-if规则下)。标准中明确提到复制/移动省略的原因是,如果复制/移动构造函数有副作用,可能会改变程序的行为。允许编译器执行这种优化,即使它改变了程序的行为。这就是为什么你的复制/移动构造函数不应该有副作用,因为那样你的程序将有多个有效的执行路径。
您可以将-fno-elide-constructors
选项传递给gcc
以确保永远不会执行此优化。
我认为这就是你所说的复制省略(即防止对象的复制)并直接使用它。参见:复制省略:移动构造函数不调用时使用三元表达式在返回语句?
你是返回值优化的"受害者"。
请注意:"在c++中,允许改变结果程序的可观察行为是特别值得注意的"。
EDIT:因此,即使move- action (cout)的副作用已经改变,编译器也可以应用优化。
- 将对象移动到std::shared_ptr
- 何时在引用或唯一指针上使用移动语义
- 如何从具有移动语义的类对象中生成共享指针
- 将shared_ptr移动到<StructA>shared_ptr<变体<结构A、结构 B>>
- C / C++ 移位/偏移/向左或向右移动位图?
- MSVC将仅移动结构参数解释为指针
- 自定义先决条件对移动分配运算符有效吗
- 返回值优化:显式移动还是隐式
- 当有分配器意识的容器被复制/移动时,反弹分配器是否被复制/移走
- 为什么复制而不是移动数据元素?
- 可以使用移动语义更改或改进此C++代码吗?
- 使lambda不可复制/不可移动
- c++在使用指针时移动语义
- 将QGraphicsItem的移动区域限制在多边形区域内
- SendInput()鼠标移动计算
- 按值 C++ 返回时进行双倍移动
- 移动二维数组中的字符
- 为什么不调用移动构造函数?(默认情况下只有构造器,没有别的)
- 安全到标准:移动会员?
- OpenVR:向视图方向移动