为何通过构造函数返回对象时无临时对象?构造过程解析
关于Stonewt类构造函数返回对象的执行流程与临时对象疑问解析
嘿,我来帮你拆解这个问题——先从你给出的代码片段入手(我补全了缺失的部分以便分析),一步步梳理执行流程,再解释为什么你感觉不到临时对象的存在。
完整代码示例
#include <iostream> using namespace std; class Stonewt { private: double pounds; // 假设类中包含该成员变量 public: // 拷贝构造函数 Stonewt(const Stonewt & obj1) { cout << "Copy constructor shows up." << endl; pounds = obj1.pounds; } // 转换构造函数(double 转 Stonewt) Stonewt(double lbs) { cout << "Construct object in lbs." << endl; pounds = lbs; } // 析构函数 ~Stonewt() { cout << "Deconstruct object." << endl; } // 友元重载减法运算符 friend Stonewt operator-(const Stonewt & obj1, const Stonewt & obj2); }; Stonewt operator-(const Stonewt & obj1, const Stonewt & obj2) { double pounds_tmp = obj1.pounds - obj2.pounds; return Stonewt(pounds_tmp); // 通过构造函数返回对象 }
一、构造函数返回对象的执行流程
假设我们在主函数中执行以下代码:
int main() { Stonewt a(10.5); Stonewt b(5.2); Stonewt c = a - b; return 0; }
正常情况下(无编译器优化)的执行步骤是:
- 构造对象
a:调用Stonewt(double lbs),输出Construct object in lbs. - 构造对象
b:同样调用转换构造函数,输出相同内容 - 进入
operator-函数:计算得到pounds_tmp = 10.5 - 5.2 = 5.3 - 创建临时对象:调用
Stonewt(5.3),输出Construct object in lbs. - 拷贝临时对象到
c:调用拷贝构造函数,输出Copy constructor shows up. - 临时对象析构:输出
Deconstruct object. - 程序结束,依次析构
c、b、a:输出三次Deconstruct object.
但实际运行时你很可能看不到第5、6步的输出,这就涉及到你第二个疑问的核心了。
二、为什么没有产生可见的临时对象?
这是因为C++编译器的返回值优化(Return Value Optimization, RVO)——这是标准允许的一种优化手段,目的是避免不必要的临时对象创建和拷贝开销。
具体到你的代码中:
- 当
operator-直接返回一个临时对象(return Stonewt(pounds_tmp);)时,编译器会跳过临时对象的创建,直接在调用方的目标对象(也就是c)的内存空间上构造这个返回对象。 - 这种优化会完全省略拷贝构造函数的调用和临时对象的析构过程,所以你看不到对应的输出,也就感觉不到临时对象的存在。
如果你想验证优化前的完整流程,可以关闭编译器的RVO优化:
- 对于GCC/Clang,编译时添加选项
-fno-elide-constructors - 对于MSVC,使用
/Od禁用所有优化
此时就能看到拷贝构造函数和临时对象析构的输出了。
内容的提问来源于stack exchange,提问作者Guodong Hu
相关产品推荐
相关产品推荐

