C++ 复制构造、构造和赋值问题
-
20-09-2019 - |
题
以下是《C++ Gotchas》一书第 56 条的摘录:
看到y对象的简单初始化写成三种不同的方式,就好像它们是等效的一样,并不少见。
Y a( 1066 );
Y b = Y(1066);
Y c = 1066;
实际上,这三个初始化都可能导致生成相同的对象代码,但它们并不等于。A的初始化称为直接初始化,它确实确实可以期望。初始化是通过直接调用y :: y(int)来完成的。
B和C的初始化更为复杂。实际上,它们太复杂了。这些都是复制初始化。在B初始化的情况下,我们请求创建Y型的匿名临时性,并用值1066初始化。然后,我们将此匿名临时性用作y类复制构造函数的参数,以初始化b。最后,我们称匿名临时性为攻击者。
为了测试这一点,我做了一个带有数据成员的简单类(程序附在最后),结果令人惊讶。对于 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 的结果。准确地说,我期望创建一个空对象,然后创建一个对象并将其分配给该空对象。实际上,对象是由复制构造函数创建的。
解决方案
的语法
X a = b;
其中a和b是X型的始终意味着拷贝构造。不管变体,如:
X a = X();
被使用,没有分配在进行,且从未有过。构造,并分配将是这样的:
X a;
a = X();
其他提示
在允许编译器优化箱子b
和c
是相同a
。此外,复制构造和赋值运算符调用可以完全由编译器消除了,所以你看什么并不一定是不同的编译器,甚至编译器设置相同。
从 C++17 开始,这三个都 是 等效(除非 Y::Y(int)
是 explicit
, ,这将根本不允许 c
)因为通常所说的 强制复制省略.
甚至 Y c = 1066;
只创建一个 Y
object 因为隐式转换的结果为 Y
是用于初始化的纯右值 c
而不是创建一个临时的。