(之前我问过这个问题,但没有给出一个可行的例子,所以我删除了之前的一个。我希望在这个问题上我得到了正确的例子。)
案例:
#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期望的'内置直接赋值',并且rvalue是其右对齐。
我已经阅读了一些关于左值到右值转换的SO问题,但我仍然不确定它是否涉及复制对象,如果有,那么它是什么类型的复制。
假设我们正在讨论班级类型。
来自[conv.lval] / 2:
否则,如果T具有类类型,则转换复制 - 从glvalue初始化类型T的临时值,转换结果是临时的prvalue。
因此,作为左值到右值转换的一部分,涉及复制初始化。
以ref = s2;
为例,使用用户定义的复制构造函数,例如打印'复制',是否会在执行上述声明时打印'复制'?
嗯,显然它不会。但这意味着我在这里误解了一些东西。
lvalue-to-rvalue转换期间的复制初始化是否与普通memcpy类似,而不是完全意义上的复制初始化?
这一切是如何运作的? :)
答案 0 :(得分:1)
据我了解,
Map<String, Pair<String, Integer>> map = new HashMap<>(); words.forEach(word -> map.merge( word, new Pair<>(word, 1), (o, n) -> { o.setSecond(o.getSecond() + n.getSecond()); return o; })); Collection<Pair<String, Integer>> result = map.values();
;包括l2r转换,因为它是每个cppreference期望的'内置直接赋值',并且rvalue是其右对齐。
你的错误在于解释赋值运算符这里是一个内置函数。它不是。唯一具有内置赋值运算符的类型是基本类型(指针,ref = s2
,char
等。)您拥有的是类类型,它具有重载的赋值运算符(无论是否为用户) - 由编译器提供或隐式生成。)
int
只需调用ref = s2;
即可。它的行为就像您刚输入S::operator=(S const&)
一样。该函数的实现中没有左值到右值的转换,因此不会生成其他副本。所有这一切都是打印出来的。没有额外的副本初始化等。
如果您以不同方式实现了赋值运算符,则为:
ref.operator=(s2)
然后,为了实际调用这个函数,会发生左值到右值的转换,你会看到你的拷贝构造函数被调用。