对于这个程序
#include <iostream>
using std::cout;
struct C
{
C() { cout << "Default C called!\n"; }
C(const C &rhs) { cout << "CC called!\n"; }
};
const C f()
{
cout << "Entered f()!\n";
return C();
}
int main()
{
C a = f();
C b = a;
return 0;
}
我得到的输出是:
Entered f()!
Default C called!
CC called!
由于f()
按值返回,因此应返回临时值。由于T a = x;
是T a(x);
,它是否会调用复制构造函数来构造a
,并将临时传入作为其参数?
答案 0 :(得分:14)
由于
f()
按值返回,因此应返回临时值。由于T a = x;
是T a(x);
,它是否会调用复制构造函数来构造a
,并将临时传入作为其参数?
查找返回值优化。这是默认打开的。如果您使用的是MSVC 2005+,则可以使用/Od
将其关闭并获得所需的结果(或GCC上的-fno-elide-constructors
)。此外,对于MSVC,请参阅this文章。
12.8复制类对象
15 当满足某些条件时,a 允许实现省略 复制类对象的构造, 即使是复制构造函数和/或 对象的析构函数有侧面 效果。在这种情况下, 实现对待源和 省略的复制操作的目标 仅仅是两种不同的方式 指的是同一个对象,而且 该对象的破坏发生在 两个时代的晚些时候 对象会有 没有了就被摧毁了 优化.15这种复制的省略 允许操作 以下情况(可能是 结合消除多重 副本):
- 在a的return语句中 具有类返回类型的函数 当表达式是a的名称时 用非易失性自动对象 同样的cv-unqualified类型 函数返回类型,副本 操作可以省略 构造自动对象 直接进入函数的返回 值 - 在一个throw-expression中,何时 操作数是a的名称 非易失性自动对象, 从操作数复制操作到 异常对象(15.1)可以省略 通过构造自动对象 直接进入异常对象
- 当一个临时的类对象有 没有受到参考(12.2) 将被复制到一个类对象 相同的cv-unqualified类型,副本 操作可以省略 构造临时对象 直接进入了目标 省略副本
- 什么时候 例外的异常声明 handler(第15条)声明一个对象 相同类型(除了 cv-qualification)作为例外 对象(15.1),复制操作即可 通过治疗来省略 exception-declaration作为别名 异常对象,如果的含义 该计划将保持不变,除了 用于执行构造函数和 声明的对象的析构函数 异常声明。
注意:强调我的
答案 1 :(得分:4)
这是编译器支持的返回值优化(RVO)功能的示例。
按值返回时,可能无法调用复制构造函数 。
在GCC上使用-fno-elide-constructors
选项关闭该功能。
答案 2 :(得分:2)
我相信它被称为return value optimization。
我假设当f()
返回C
对象时,对象被分配在调用方法的堆栈空间中,因此不需要复制来初始化C a
。这是您的default C called
。
C b = a
这会导致复制构造函数为CC called
。
顺便说一句,wiki上的示例与您的代码非常相似。