以下是《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();

其他提示

在允许编译器优化箱子bc是相同a。此外,复制构造和赋值运算符调用可以完全由编译器消除了,所以你看什么并不一定是不同的编译器,甚至编译器设置相同。

从 C++17 开始,这三个都 等效(除非 Y::Y(int)explicit, ,这将根本不允许 c)因为通常所说的 强制复制省略.

甚至 Y c = 1066; 只创建一个 Y object 因为隐式转换的结果为 Y 是用于初始化的纯右值 c 而不是创建一个临时的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top