为何调用g函数时未触发copy-ctor?探究Move-ctor与copy-ctor调用时机
关于C++中拷贝/移动构造函数未被调用的问题解答
兄弟,你遇到的这个情况,核心原因是GCC 4.8.2默认开启了返回值优化(Return Value Optimization,简称RVO)——这是编译器的一种性能优化手段,它会直接在调用者的栈帧上构造函数返回的临时对象,完全跳过拷贝或移动构造函数的调用,以此减少不必要的对象拷贝开销。
先搞清楚:正常情况下拷贝/移动构造什么时候会被调用?
如果没有编译器优化的干预,这些场景会触发对应的构造函数:
- 用一个已存在的左值对象初始化新对象(比如
MyClass a = b;,b是已经创建好的对象),此时会调用拷贝构造函数; - 用右值(比如临时对象、被
std::move()转换后的对象)初始化新对象时,C++11及以后会调用移动构造函数; - 函数按值返回对象时,原本会先在函数栈帧里构造局部对象,再把它拷贝/移动到返回值的临时存储空间中。
为什么你的g函数里没触发拷贝构造?
回到你的场景,当函数返回一个局部对象时,GCC的RVO会直接“偷懒”:它不会先在函数内部构造局部对象,再拷贝出去,而是直接在调用者准备接收返回值的内存位置构造这个对象。这种优化是C++标准明确允许的,就算你把移动构造函数显式delete掉,编译器依然可以用RVO跳过拷贝/移动步骤。
要是你想验证这个结论,只需要在编译时关闭RVO优化就行:
g++ -fno-elide-constructors your_code.cpp
加上这个编译参数后,编译器就会老老实实按照“构造局部对象→调用移动/拷贝构造”的流程执行,你就能看到对应的构造函数调用日志了。
再补充下移动构造的典型触发场景
除了刚才说的右值初始化,这些情况也会调用移动构造:
- 函数按值返回对象,但编译器没法做RVO的时候(比如函数根据不同分支返回不同的局部对象);
- 用
std::move()把左值强制转成右值引用,比如MyClass a = std::move(b);,这时候会把b的资源转移给a; - 容器的扩容操作(比如std::vector的push_back当内存不够时),会把旧内存里的元素移动到新内存中。
最后提一句:RVO是个非常实用的优化,平时写代码根本不用管它,编译器会自动处理好对象的生命周期。只有当你需要调试构造函数的调用逻辑时,再用-fno-elide-constructors关闭优化就行。
内容的提问来源于stack exchange,提问作者klaus
相关产品推荐
相关产品推荐

