初始化具有函数返回值的对象时未复制的复制构造函数

cri*_*ron 9 c++ copy-constructor temporary-objects return-value-optimization copy-elision

请考虑以下代码:

#include <iostream>

using namespace std;

class A
{
    public:
        int a;
        A(): a(5)
        {
           cout << "Constructor\n";
        }
        A(const A &b)
        {
            a = b.a;
            cout << "Copy Constructor\n";
        }
        A fun(A a)
        {
            return a;
        }
};

int main()
{
    A a, c;
    A b = a.fun(c);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

上面代码的输出g++ file.cpp是:

Constructor
Constructor
Copy Constructor
Copy Constructor
Run Code Online (Sandbox Code Playgroud)

上面代码的输出g++ -fno-elide-constructors file.cpp是:

Constructor
Constructor
Copy Constructor
Copy Constructor
Copy Constructor
Run Code Online (Sandbox Code Playgroud)

我知道返回值优化.我的问题是哪个复制构造函数的调用被删除(返回期间的临时对象或被复制到b的返回对象)?

如果省略的复制构造函数是用于创建b的构造函数,那么如何创建b(因为在这种情况下也没有构造函数调用)?

如果我替换行A b = a.fun(c);a.fun(c)和使用第一种方法或者甚至第二方法进行编译,则还复制构造是被称为2次.因此,如果在上一段中解释的情况下,临时对象的复制构造函数被省略了,那么为什么在这种情况下它没有被省略呢?

Ide*_*Hat 6

#include <iostream>

using namespace std;

class A
{
public:
    int a;
    A(): a(5)
    {
        cout << "Constructing: " << (void *)this << std::endl;
    }
    A(const A &b)
    {
        a = b.a;
        cout << "Copy Constructor: " << (void *)this << " from " << (void *)&b << std::endl;
    }
    A fun(A a)
    {
        return a;
    }
};

int main()
{

    A a, c;
    A b = a.fun(c);

    std::cout << "a:" << (void *)&a << std::endl <<
              "b:" << (void *)&b << std::endl <<
              "c:" << (void *)&c << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

产量:

Constructing: 0x7fffbb377220
Constructing: 0x7fffbb377210
Copy Constructor: 0x7fffbb377230 from 0x7fffbb377210
Copy Constructor: 0x7fffbb377200 from 0x7fffbb377230
a:0x7fffbb377220
b:0x7fffbb377200
c:0x7fffbb377210
Run Code Online (Sandbox Code Playgroud)

因此它构造a,构造c,复制c到中间体(函数的参数a),然后将中间体直接b复制到,跳过典型的a复制到返回中间体.如果您通过值传递,则更好地证明了这一点(更改为A fun(const A& a):

Constructing: 0x7fff8e9642b0
Constructing: 0x7fff8e9642a0
Copy Constructor: 0x7fff8e964290 from 0x7fff8e9642a0
a:0x7fff8e9642b0
b:0x7fff8e964290
c:0x7fff8e9642a0
Run Code Online (Sandbox Code Playgroud)

a构造,c构造,c直接复制到b,尽管b没有传递给乐趣!