以下代码仅打印A::A()
,但不打印A::A(const A&)
或operator=
。为什么呢?
struct A
{
A() { cout << "A::A()" << endl; }
A(const A& value) { cout << "A::A(const A&)" << endl; }
A& operator=(const A& newValut)
{
cout << "A::operator=" << endl;
return *this;
}
};
A foo()
{
A a; //Ok, there we have to create local object by calling A::A().
return a; //And there we need to copy it, otherwise it will be destroyed
//because it's local object. But we don't.
}
int main()
{
A aa = foo(); //Also there we need to put result to the aa
//by calling A::A(const A&), but we don't.
}
所以这段代码必须打印
A::A()
A::A(const A&)
A::A(const A&)
但事实并非如此。为什么呢?
我建议foo()
下的g++
没有优化内容。
答案 0 :(得分:10)
这称为"Return Value Optimization"。在这种情况下,允许编译器忽略副本。
答案 1 :(得分:3)
这是在C ++中返回复杂类型的方式:返回对象的位置实际上是在调用函数之前由调用者提供的,并且指向这个尚未初始化的对象的指针作为隐藏参数传递给功能。该函数使用此内存位置从返回的表达式构造返回的对象。
因此,当返回的对象要直接初始化程序A aa = foo();
中的新对象时,它不需要将返回的值复制到堆栈上的对象。它要求函数直接在此位置创建对象。因此,只需要对复制构造函数进行一次调用。 (事实上,如果您有2次调用复制构造函数,则C ++编译器将不兼容)。
现在,最重要的是,允许编译器在称为“返回值优化”或RVO的优化中优化此调用。怎么可能?如果查看代码,可以看到可以在返回值的建议位置直接在foo()中定义本地“a”变量,因此不必再次复制它。这是一个重要的特性,因为复制构造函数可能很复杂且运行缓慢,因此这可以在实现时显着提高性能(并且我知道的每个编译器都实现了此功能)。
因此,在您的情况下,根据编译器的不同,您可能会对复制构造函数进行1或0调用,并且您的编译器仍然符合要求。