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

时间:2018-01-29 02:13:07

标签: c++ c++14 copy-constructor lvalue-to-rvalue value-categories

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

案例:

#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类似,而不是完全意义上的复制初始化?

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

1 个答案:

答案 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 = s2char等。)您拥有的是类类型,它具有重载的赋值运算符(无论是否为用户) - 由编译器提供或隐式生成。)

int只需调用ref = s2;即可。它的行为就像您刚输入S::operator=(S const&)一样。该函数的实现中没有左值到右值的转换,因此不会生成其他副本。所有这一切都是打印出来的。没有额外的副本初始化等。

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

ref.operator=(s2)

然后,为了实际调用这个函数,会发生左值到右值的转换,你会看到你的拷贝构造函数被调用。