0

(我之前问过这个问题,但没有给出一个可行的例子,所以我删除了前一个。我希望在这个问题上我得到了正确的例子。)

案子:

#include <iostream>

struct S
{
    S() = default;

    S(const S &)
    {
        std::cout << "Copying" << std::endl;
    }

    S& operator=(const S &)
    {
        std::cout << "Copy assignment" << std::endl;
        return *this;
    }
};

int main()
{
    S s{};
    S s2{};
    S &ref = s;
    ref = s2;
}

据我了解,ref = s2;包括 l2r 转换,因为它是每个 cppreference 期望的“内置直接分配”,并且右值作为其正确的参数。

我已经阅读了一些关于左值到右值转换的 SO 问题,但我仍然不确定它是否涉及对象的复制,如果涉及,它是哪种复制。

假设我们正在谈论类类型。

来自 [conv.lval]/2:

否则,如果 T 具有类类型,则转换从泛左值复制初始化 T 类型的临时,并且转换的结果是临时的纯右值。

因此,作为左值到右值转换的一部分,涉及到复制初始化。

因此,以用户定义的复制构造函数为例ref = s2;,例如打印“Copying”,在上述语句的执行过程中会打印“Copying”吗?

嗯,显然不会。但这意味着我在这里误解了一些东西。

左值到右值转换期间的复制初始化是否类似于普通的 memcpy 而不是完全意义上的复制初始化?

这一切是如何运作的?:)

4

1 回答 1

2

据我了解,ref = s2; 包括 l2r 转换,因为它是每个 cppreference 期望的“内置直接分配”,并且右值作为其正确参数。

你的错误是在这里解释赋值运算符是一个内置的。它不是。唯一具有内置赋值运算符的类型是基本类型(指针、charint等)。您拥有的是类类型,它具有重载的赋值运算符(无论是用户提供的还是由编译器隐式生成的)。

ref = s2;简单地调用S::operator=(S const&). 它的行为就像您刚刚键入了ref.operator=(s2). 在该函数的实现中没有左值到右值的转换,因此不会制作其他副本。所发生的只是该行被打印出来。无需额外的复制初始化等。

如果您以不同方式实现赋值运算符,例如:

S& operator=(S /* no ref */) { return *this; }

然后会发生左值到右值的转换,以便实际调用这个函数,你会看到你的复制构造函数被调用。

于 2018-01-29T02:44:42.860 回答