为何代码中无任何拷贝/移动构造函数被调用?(GCC环境)
问题分析:C++移动构造函数未被调用的原因
代码示例
#include <iostream> using namespace std; struct foo{ int x; double y; double z; foo(int x_,double y_,double z_) { x = x_; y = y_; z = z_; } foo(const foo& f){ cout<<"foo copy for const ref called"<<endl; x = f.x; y = f.y; srand((unsigned ) time(nullptr)); int z_ = rand(); z = z_; cout<<f.x<<endl; } foo(foo&& f) { cout<<"foo copy for right ref called"<<endl; x = f.x; y = f.y; srand((unsigned ) time(nullptr)); int z_ = rand(); z = z_; cout<<f.x<<endl; } }; int main() { srand((unsigned ) time(nullptr)); int rand_ = rand(); foo f_(foo(rand_, 2, 3)); cout<<f_.x<<' '<<f_.y<<' '<<f_.z<<endl; }
运行输出
21862 2 3
疑问
原本预期foo(foo&& f)(移动构造函数)会被调用,且f_.z为随机值,但实际无任何拷贝构造函数被触发,f_.z的值为3,请问这是为什么?
解答
这是因为**复制消除(Copy Elision)规则中的返回值优化(RVO)**在起作用,这是C++标准明确允许的优化行为。
在代码语句foo f_(foo(rand_, 2, 3));中,从语法上看是先构造一个临时foo对象,再用这个临时对象去初始化f_,但C++标准允许编译器直接跳过临时对象的创建步骤,直接在f_的内存空间上调用foo(int, double, double)构造函数完成初始化——完全不需要触发移动或拷贝构造函数。
GCC在默认编译选项下(即使是-O0无优化模式)也会执行这个优化,所以你看不到移动/拷贝构造函数的输出,f_.z直接被初始化为3,而非移动构造函数中生成的随机值。
如果想要强制触发移动构造函数,可以给GCC添加编译选项-fno-elide-constructors,禁用复制消除优化,此时编译器会先创建临时对象,再调用移动构造函数初始化f_,就能得到你预期的输出。
另外注意:即便显式使用std::move包装临时对象(如foo f_(std::move(foo(rand_, 2, 3)));),编译器仍可能执行复制消除;只有加上-fno-elide-constructors选项,才能确保移动构造函数被调用。
内容的提问来源于stack exchange,提问作者Lucy
相关产品推荐
相关产品推荐

