Bos*_*gan 11 c++ constructor copy-constructor
这是一个小代码片段:
class A
{
public:
A(int value) : value_(value)
{
cout <<"Regular constructor" <<endl;
}
A(const A& other) : value_(other.value_)
{
cout <<"Copy constructor" <<endl;
}
private:
int value_;
};
int main()
{
A a = A(5);
}
Run Code Online (Sandbox Code Playgroud)
我假设输出将是"常规构造函数"(对于RHS),后面是LHS的"复制构造函数".所以我避免使用这种风格并始终将类的变量声明为A a(5);.但令我惊讶的是上面的代码从未调用过复制构造函数(Visual C++ 2008)
有没有人知道这种行为是由编译器优化,还是C++的一些记录(和可移植)功能引起的?谢谢.
GMa*_*ckG 14
从另一个评论:"所以默认情况下我不应该依赖它(因为它可能取决于编译器)"
不,它实际上无论如何都不依赖于编译器.任何值得一粒沙子的编译器都不会浪费时间构建A,然后将其复制过来.
在标准中它明确地说,完全可以接受T = x;等同于说T(x);.(§12.8.15,第211页)这样做T(T(x))显然是多余的,所以它消除了内在T.
要获得所需的行为,您将强制编译器默认构造第一个A:
A a;
// A is now a fully constructed object,
// so it can't call constructors again:
a = A(5);
Run Code Online (Sandbox Code Playgroud)
我正在研究这个问题,以回答另一个作为欺骗而被关闭的问题,所以为了不让工作浪费,我正在回答这个问题.
表单的声明A a = A(5)称为变量的复制初始化a.C++ 11标准,8.5/16表示:
选择的函数以初始化表达式作为参数调用; 如果函数是构造函数,则调用初始化目标类型的cv-nonqualified版本的临时函数.临时是一个prvalue.然后,根据上面的规则,调用的结果(对于构造函数的情况是临时的)用于直接初始化作为复制初始化目标的对象.在某些情况下,允许实现通过将中间结果直接构造到正在初始化的对象中来消除此直接初始化中固有的复制; 见12.2,12.8.
这意味着编译器会查找相应的构造函数来处理A(5),创建临时文件并将其临时复制到a.但在什么情况下可以删除副本?
让我们看看12.8/31说:
当满足某些条件时,允许实现省略类对象的复制/移动构造,即使该对象的复制/移动构造函数和/或析构函数具有副作用.在这种情况下,实现将省略的复制/移动操作的源和目标视为仅仅两种不同的引用同一对象的方式,并且该对象的销毁发生在两个对象的后期时间.没有优化就被破坏了.复制/移动操作的省略,称为复制省略,在以下情况下允许(可以合并以消除多个副本):
[...]
- 当一个未绑定到引用(12.2)的临时类对象被复制/移动到具有相同cv-nonqualified类型的类对象时,可以通过将临时对象直接构造到目标中来省略复制/移动操作省略的复制/移动
牢记这一切,这是表达式发生的事情A a = A(5):
A(int)构造被选择为初始化一个临时对象A与复制初始化表达式中的目标类型具有相同的类型,所以允许编译器直接构造对象a,省略临时对象