为什么不调用复制构造函数将临时对象复制到新定义的对象

时间:2013-05-25 13:15:46

标签: c++ visual-studio-2010

#include <iostream>
using namespace std;

class Y {
public:
    Y(int ) {
        cout << "Y(int)\n";
    }
    Y(const Y&) {
        cout << " Y(const Y&)\n";
    }
};

int main() {
    Y obj1 = 2; // Line 1
}

输出:Y(int)

预期输出:Y(int)                  Y(const Y&amp;)

问题&GT;根据我的理解,第1行将首先创建一个临时对象Y(2),然后将临时对象分配给obj1。因此,我希望调用Y(int)Y(const Y&)。但是vs2010的输出仅报告第一个(即Y(int))。为什么呢?

3 个答案:

答案 0 :(得分:10)

  

为什么?

因为在某些条件下(由C ++ 11标准的第12.8 / 31段指定),即使这些特殊函数(或析构函数)具有副作用,也可以省略对复制构造函数或移动构造函数的调用:

  

这种复制/移动的省略   在下列情况下允许称为复制省略的操作(可以合并为   消除多份副本):

     

- [...]

     

- 当复制/移动尚未绑定到引用(12.2)的临时类对象时   对于具有相同cv-unqualified类型的类对象,可以省略复制/移动操作   将临时对象直接构造到省略的复制/移动

的目标中      

- [...]

这是所谓的“ as-if ”规则的唯一例外,它通常会限制编译器可以对程序执行的转换(优化)的类型,以便保留它可观察的行为。

请注意,上述机制称为 copy elision - 即使它实际上是对被删除的移动构造函数的调用。

答案 1 :(得分:4)

这是因为构造函数只有一个参数而且没有标记为explicit,因此编译器会自动转换:

Y obj1 = 2;

分为:

Y obj1(2);

要防止此行为,请使用:

explicit Y(int ) {
    cout << "Y(int)\n";
}

(在你的情况下编译将失败)。

答案 2 :(得分:3)

这称为copy initializationY(int )是转换构造函数。

  

没有函数声明的单参数构造函数   说明符明确

允许编译器忽略额外的副本并使用您的conversion constructor。这意味着

Y obj1 = 2; // Line 1

相当于

Y obj1(2); // Line 1