9
#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&)

问题> 根据我的理解,第 1 行会先创建一个临时对象 Y(2),然后将临时对象赋值给obj1. 因此,我期望两者Y(int)Y(const Y&)被调用。但是 vs2010 的输出只报告第一个(即Y(int))。为什么?

4

3 回答 3

10

为什么?

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

这种复制/移动操作的省略,称为复制省略,在以下情况下是允许的(可以结合起来消除多个副本):

— [...]

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

— [...]

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

请注意,上述机制称为复制省略——即使它实际上是对被省略的移动构造函数的调用。

于 2013-05-25T13:17:26.183 回答
4

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

Y obj1 = 2;

进入:

Y obj1(2);

要防止这种行为,请使用:

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

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

于 2013-05-25T13:17:52.560 回答
3

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

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

允许编译器省略额外的副本并使用您的conversion constructor. 意思是

Y obj1 = 2; // Line 1

相当于

Y obj1(2); // Line 1
于 2013-05-25T13:17:52.497 回答