#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)
)。为什么呢?
答案 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 initialization
。 Y(int )
是转换构造函数。
没有函数声明的单参数构造函数 说明符明确
允许编译器忽略额外的副本并使用您的conversion constructor
。这意味着
Y obj1 = 2; // Line 1
相当于
Y obj1(2); // Line 1