1

可能重复:
为什么在这种情况下不调用复制构造函数?

考虑以下代码片段:

#include <iostream>

using namespace std;

class Test
{
        char name[16];
        public:
        Test ()
        {
                cout <<"Inside Constructor"<<endl;
        }

        Test (const Test & t)
        {
                cout <<"Inside Copy Constructor "<<endl;
        }

};

Test f()
{
        return Test();
}

int main ( int argc, char ** argv)
{
        Test t;
        Test t1 = f();

}

Test t1= f() -> 它调用 f(),并返回 Test 对象,然后根据我的理解应该调用复制构造函数。但我得到以下输出:

Inside Constructor
Inside Constructor

我的理解有什么问题?

4

4 回答 4

2

这里发生了两个复制省略。

第一种是返回值优化(不是将表达式的结果复制Test()到作为 的返回值的临时对象中,而是通过直接构造到作为 的返回值的临时对象中来评估f表达式)。Test()f

第二个是从初始化表达式的复制t1t1自身的省略(因此不是复制作为的返回值ft1临时,而是f直接构造作为的返回值的临时t1)。

这两个省略链在一起——所以t1构造返回值时将内存用作目标,构造时将返回值f的内存f用作目标Test()。所以实际上t1是由无参数构造函数直接初始化的,不需要副本。

复制构造函数省略在 C++03 的 12.8/15 和 C++11 的 12.8/31 的标准中定义(也允许移动省略)。它需要特定的权限,因为它会更改程序的可观察行为(在您的情况下,它省略了复制构造函数的副作用,即输出)。所以只能在标准规定的条件下进行。

当源是临时的时,这两个省略都是C++03 中第二个允许的省略(C++11 中的第三个)的示例。

第一个允许的省略通常称为“命名返回值优化”,当源不是临时的时,它允许省略特定类型的副本。

于 2012-10-18T08:44:37.753 回答
1

因为返回值优化消除了所需的额外副本。

于 2012-10-18T08:29:23.200 回答
1

这称为返回值优化

于 2012-10-18T08:29:33.233 回答
0

好吧,我认为您永远不会调用复制构造函数。您调用默认构造函数,获取临时副本,然后调用赋值运算符。

编辑。好的,我看错了Test t1 = f();。RVO 确实很可能正在发挥作用f()。所以它本质上等于Test t1 = Test();

我认为这是允许应用的一些优化之一,即使它会导致程序的行为发生变化。如果您使用优化标志进行处理,您可能可以让它执行复制构造函数(旧对象上的 + 析构函数)。

于 2012-10-18T08:34:42.137 回答