类类型的左值到右值转换:是否涉及复制?
Lvalue-to-rvalue conversion for class types: is there copying involved?
(我之前问过这个问题,但没有给出一个可行的例子,所以我删除了前一个。我希望在这个问题上我得到了正确的例子。
箱:
#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 首选项期望的"内置直接赋值",并将右值作为其正确参数。
您的错误在于解释赋值运算符,这里是内置的。不是。具有内置赋值运算符的唯一类型是基本类型(指针、char
、int
等)。您拥有的是一个类类型,它有一个重载赋值运算符(无论是用户提供的还是由编译器隐式生成的)。
ref = s2;
只是调用S::operator=(S const&)
。它的行为就像您刚刚键入ref.operator=(s2)
一样。在该函数的实现中没有左值到右值的转换,因此不会创建其他副本。发生的所有情况都是打印该行。无需额外的副本初始化等。
如果以不同的方式实现赋值运算符,则为:
S& operator=(S /* no ref */) { return *this; }
然后,将按实际调用此函数的方式进行左值到右值的转换,并且您将看到复制构造函数被调用。
- 是否可以初始化不可复制类型的成员变量(或基类)
- 当有分配器意识的容器被复制/移动时,反弹分配器是否被复制/移走
- C++矢量复制构造函数和赋值运算符是否也复制保留空间?
- 将对象的字节复制到数组并再次复制回来是否安全
- 是否可以将不可复制的成员用作使对象不可复制的替代方法?
- 是否可以/希望创建不可复制的共享指针模拟(以启用weak_ptr跟踪/借用类型语义)?
- 如果这不是类的"复制构造函数",是否可以移动对象?
- 在这种情况下,使用 string_view 是否会导致不必要的字符串复制?
- 为什么复制构造函数不需要检查输入对象是否指向自身?
- 除了 std::vector 之外,是否有一个 std 容器不会复制和销毁作为类的元素?
- 如何检查文件是否复制成功?(便携式解决方案)C++
- 在此示例中,向量是否复制了两次
- 修改时是否复制C++中的字符串
- OpenMP 是否复制私有对象
- STL 集合的插入方法是否复制传递对象的值?
- 继承中的基类是否复制到派生类
- 在结构中复制构造函数:是否复制数组
- 成员初始化列表是否复制字符串C++
- 这是否复制了矢量
- Mat::p ush_back(x) 是否复制 x 元素