【发布时间】:2011-01-28 14:22:30
【问题描述】:
这是《C++ Gotchas》一书第 56 条的摘录:
看到一个简单的并不少见 Y 对象的初始化写入 三种不同方式中的任何一种,好像 它们是等价的。
Y a( 1066 );
Y b = Y(1066);
Y c = 1066;
事实上,所有这三个 初始化可能会导致 在同一个目标代码中 生成,但它们不等价。 a 的初始化称为 a 直接初始化,它确实 正是人们所期望的。这 初始化是通过 直接调用 Y::Y(int)。
b 和 c 的初始化是 更复杂。其实他们也 复杂的。这两个都是副本 初始化。在这种情况下 b的初始化,我们要求 创建一个匿名临时 Y 类型,用值初始化 1066. 然后我们使用这个匿名临时作为参数来复制 用于初始化类 Y 的构造函数 湾。最后,我们调用析构函数 匿名临时。
为了测试这一点,我做了一个带有数据成员的简单类(程序附在末尾),结果令人惊讶。似乎对于 c 的情况,对象是由复制构造函数构造的,而不是像书中建议的那样。
有人知道语言标准是否发生了变化,或者这仅仅是编译器的优化功能吗?我使用的是 Visual Studio 2008。
代码示例:
#include <iostream>
class Widget
{
std::string name;
public:
// Constructor
Widget(std::string n) { name=n; std::cout << "Constructing Widget " << this->name << std::endl; }
// Copy constructor
Widget (const Widget& rhs) { std::cout << "Copy constructing Widget from " << rhs.name << std::endl; }
// Assignment operator
Widget& operator=(const Widget& rhs) { std::cout << "Assigning Widget from " << rhs.name << " to " << this->name << std::endl; return *this; }
};
int main(void)
{
// construct
Widget a("a");
// copy construct
Widget b(a);
// construct and assign
Widget c("c");
c = a;
// copy construct!
Widget d = a;
// construct!
Widget e = "e";
// construct and assign
Widget f = Widget("f");
return 0;
}
输出:
Constructing Widget a
Copy constructing Widget from a
Constructing Widget c
Assigning Widget from a to c
Copy constructing Widget from a
Constructing Widget e
Constructing Widget f
Copy constructing Widget from f
我对构造 d 和 e 的结果感到最惊讶。准确地说,我期望创建一个空对象,然后创建一个对象并将其分配给空对象。实际上,对象是由复制构造函数创建的。
【问题讨论】:
-
"在初始化 b 的情况下,我们请求创建一个类型为 Y 的匿名临时对象,初始化值为 1066"...在初始化 c 时也是如此,只是更难看到临时的。
-
请注意,如果您的构造函数被声明为
explicit...,则Y c = 1006是不可能的,因为大多数时候任何一个参数构造函数都应该这样做。 -
Matthieu,是的,我同意你所说的,我在编程时总是这样做。如果我没记错的话,您的观点也包含在“更有效的 C++”一书中。
标签: c++ constructor copy-constructor assignment-operator