C++中函数返回值为自定义类时不调用复制构造函数的问题

    技术2022-07-10  100

    最近期末考试,忙着复习,ACM暂时鸽了。 复习的时候手敲了一个程序想看看编译器是怎么调析构函数的,结果出问题了。 问题是这样的:

    #include <bits/stdc++.h> using namespace std; typedef long long ll; class Complex { public: int r, i; public: Complex(int a, int b): r(a), i(b) { cout << "Constructor called." << endl; } ~Complex() { cout << "Destructor called." << endl; } Complex(const Complex &a) { r = a.r, i = a.i; cout << "Copy constructor called." << endl; } Complex operator +(Complex x1); }; Complex Complex::operator +(Complex x1) { return Complex(r + x1.r, i + x1.i); } int main() { Complex a(1, 2); a = a + a; return 0; }

    运行完结果是:

    Constructor called. Copy constructor called. Constructor called. Destructor called. Destructor called. Destructor called.

    按照书上讲的来说,这个程序首先调用一次构造函数创建对象a,之后在主程序第二行调用复制构造函数把a传给形参x1,之后在函数中调用一次构造函数生成加法的结果,之后再调用一次复制构造函数把这个结果存到一个临时对象里,然后析构结果和x1,之后把临时对象赋值给a,最后析构临时对象。所以理想结果应该是:

    Constructor called. Copy constructor called. Constructor called. Copy constructor called. Destructor called. Destructor called. Destructor called. Destructor called.

    但是很明显程序运行结果少了一次复制构造函数和析构函数的调用。百思不得其解,想了一个下午,最后通过询问神奇海螺发现C++对于返回值有个叫做返回值优化的东西。 这篇文章讲得很详细:C++中临时对象及返回值优化

    具体来说返回值优化有两种实现方式。第一种是对于已经存在的对象a,在调用函数对该对象赋值是编译器会偷偷往函数里多塞一个形参,把a的地址传进去,之后直接在函数里对a赋值。第二种不再赘述,上面这篇博客写得比较详细。

    把程序的

    a = a + a;

    改成

    a + a;

    后仍然没有调用复制构造函数。应该采用的是第二种方法。

    有错误欢迎指出。

    Processed: 0.022, SQL: 12