考虑以下代码段:
#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();
}
测试t1 = f() - &gt;它调用f(),并返回Test对象,然后根据我的理解,应该调用复制构造函数。但我得到以下输出:
Inside Constructor
Inside Constructor
我的理解有什么问题?。
答案 0 :(得分:2)
这里会出现两个副本。
第一种是返回值优化(而不是将表达式Test()
的结果复制到临时对象,即f
的返回值,表达式Test()
是通过直接构造临时对象来评估,该临时对象是f
)的返回值。
第二个是从初始化表达式t1
到t1
本身的副本的省略(因此不是将f
的返回值临时复制到{{1} }},t1
的返回值临时直接构造到f
)。
两个部门链接在一起 - 因此t1
的内存在构造t1
的返回值时用作目标,而f
的返回值的内存是在构建f
时用作目的地。因此实际上Test()
由no-args构造函数直接初始化,并且不需要副本。
复制构造函数elision在C ++ 03的12.8 / 15和C ++ 11的12.8 / 31中的标准中定义(也允许省略移动)。它需要特定的权限,因为它改变了程序的可观察行为(在您的情况下,它省略了复制构造函数的副作用,输出)。因此它只能在标准中定义的条件下执行。
这两个元素都是C ++ 03中允许的第二个允许省略的例子(C ++ 11中的第三个),当源是临时的时。
第一个允许的省略通常称为“命名返回值优化”,它允许在源不是临时源时省略特定类型的副本。
答案 1 :(得分:1)
因为return value optimisation删除了所需的额外副本。
答案 2 :(得分:1)
答案 3 :(得分:0)
好吧,我认为你永远不会调用复制构造函数。您调用默认构造函数,获取临时副本,然后调用赋值运算符。
EDIT。好的,我想念Test t1 = f();
。 RVO确实最有可能在f()
踢。
所以它基本上等于Test t1 = Test();
。
我认为这是允许应用的一些优化,即使它可能导致程序的更改行为。如果你使用优化标志进行修改,你可能会让它执行一个复制构造函数(旧对象上的+析构函数)。