在此代码中:
#include <iostream>
using std::cout;
class Foo {
public:
Foo(): egg(0) {}
Foo(const Foo& other): egg(1) {}
int egg;
};
Foo bar() {
Foo baz;
baz.egg = 3;
return baz;
}
int main(void) {
Foo spam(bar());
cout << spam.egg;
return 0;
}
输出为3
,而我预计它为1
。
这意味着不会在行Foo spam(bar())
中调用复制构造函数。
我想这是因为bar
函数没有返回引用。
您能解释一下spam
初始化时的实际情况吗?
如果这是一个愚蠢的问题,我会事先道歉。
谢谢!
答案 0 :(得分:17)
复制/移动elision是所谓的“ as-if ”规则的唯一允许例外,它通常限制允许编译器执行的转换(例如优化)的种类。一个程序。
该规则旨在允许编译器执行他们希望的任何优化,只要转换后的程序可以“好像”它是原始的一样。但是,有一个重要的例外。
根据C ++ 11标准的第12.8 / 31段:
当满足某些条件时,允许实现省略类的复制/移动构造 object,即使是为复制/移动操作选择的构造函数和/或对象的析构函数 有副作用。 [......]在下列情况下允许复制/移动操作(称为复制省略) 可以合并以消除多个副本):
- 在具有类返回类型的函数中的
return
语句中,当表达式是a的名称时 具有相同cv-unqualified的非易失性自动对象(函数或catch子句参数除外) 键入函数返回类型,可以通过构造省略复制/移动操作 自动对象直接进入函数的返回值[...]
- 当复制/移动尚未绑定到引用(12.2)的临时类对象时 对于具有相同cv-unqualified类型的类对象,可以省略复制/移动操作 将临时对象直接构造到省略的copy / move
的目标中[...]
换句话说,在12.8 / 31的规定适用的情况下,你不应该依赖复制构造函数或移动被调用的构造函数或不。