C++11移动构造行为疑问:临时变量初始化容器未触发移动操作
问题原因
这个现象是C++标准明确允许的**复制消除(Copy Elision)**优化导致的,属于合法的预期行为,你的代码没有问题。
具体原理
你编写的c2初始化代码:
Container<MoveChecker> c2 = Container<MoveChecker>(mc);
按照语法规则,右侧是Container<MoveChecker>类型的纯右值临时对象,本来应该调用移动构造函数构造c2,但C++标准允许编译器在这种场景下直接跳过临时对象的创建和移动构造流程,直接用参数mc在c2的内存空间上构造目标对象,整个过程不会调用移动构造函数,因此内部的MoveChecker的wasMoved标记不会被置为1,最终输出0。
验证方法
你可以在编译时添加-fno-elide-constructors选项关闭复制消除优化:
g++ move.cpp -o move.exe -std=c++11 -fno-elide-constructors
此时重新运行程序,c2的输出会变为1,符合你原本的预期。
c3输出为1的原因
你为c3的初始化添加了std::move调用:
Container<MoveChecker> c3 = std::move(Container<MoveChecker>(mc));
std::move会将原本的纯右值临时对象转换为亡值(xvalue),这种场景下编译器无法执行复制消除,必须调用移动构造函数完成c3的初始化,因此内部的MoveChecker的wasMoved标记被置为1,输出1。
补充说明
复制消除是C中非常重要的优化手段,从C11开始被标准允许,C++17更是将纯右值初始化同类型对象的场景下的复制消除改为强制要求,即使移动/拷贝构造函数存在可观测的副作用(比如你这里修改wasMoved标记),编译器也可以合法执行该优化。
内容的提问来源于stack exchange,提问作者Caduchon
相关产品推荐
相关产品推荐

