类类型的左值到右值转换:是否涉及复制?

Lvalue-to-rvalue conversion for class types: is there copying involved?

本文关键字:是否 复制 类型 转换      更新时间:2023-10-16

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

箱:

#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 转换,因为它是一个"内置直接赋值",每个 cpp 首选项都期望右值作为其正确的参数。

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

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

从 [conv.lval]/2:

否则,如果 T 具有类类型,则转换副本从 glvalue 初始化类型 T 的临时,转换的结果是临时的 prvalue。

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

因此,以ref = s2;为例,使用用户定义的复制构造函数,例如打印"复制",在执行上述语句期间是否会打印"复制"?

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

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

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

我了解,ref = s2; 包括 l2r 转换,因为它是每个 cpp 首选项期望的"内置直接赋值",并将右值作为其正确参数。

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

ref = s2;只是调用S::operator=(S const&)。它的行为就像您刚刚键入ref.operator=(s2)一样。在该函数的实现中没有左值到右值的转换,因此不会创建其他副本。发生的所有情况都是打印该行。无需额外的副本初始化等。

如果以不同的方式实现赋值运算符,则为:

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

然后,将按实际调用此函数的方式进行左值到右值的转换,并且您将看到复制构造函数被调用。