为什么右值引用成员是常量?

Why rvalue reference member would be const?

我正在尝试为结构编写一个移动构造函数,但我不明白为什么我无法调用结构成员的移动构造函数:

#include <memory>

struct C
{
    std::unique_ptr<int[]> mVector;
    size_t                 mSize;

    C() = default;

    C(C &&temp)
    : mVector(temp.mVector)
    , mSize(temp.mSize)
    {}    
};

当我编译这个时,我得到:

gcc -c TempTest.cpp
TempTest.cpp: In constructor 'C::C(C&&)':
TempTest.cpp:9:23: error: use of deleted function 'std::unique_ptr<_Tp [], _Dp>::unique_ptr(const std::unique_ptr<_Tp [], _Dp>&) [with _Tp = int; _Dp = std::default_delete<int []>]'
9 |     , mSize(temp.mSize)
  |                       ^
In file included from c:/msys64/mingw64/include/c++/10.3.0/memory:83,
             from TempTest.cpp:1:
c:/msys64/mingw64/include/c++/10.3.0/bits/unique_ptr.h:723:7: note: declared here
 723 |       unique_ptr(const unique_ptr&) = delete;
     |       ^~~~~~~~~~

因为在构造函数中 temp 是一个右值引用,它是非常量所以 temp.mVector 应该是非常量并且应该调用 unique_ptr 移动构造函数但是它调用了被删除的复制构造函数。知道错误在哪里吗?

Why rvalue reference member would be const?

不要假设它是 const。您应该假定 unique_ptr(const unique_ptr&) 只是可用构造函数中的 最佳匹配项

Because in constructor temp is a rvalue reference

惊喜!它不是 r 值参考。

当调用构造函数时,变量 temp 绑定 到右值。现在它是一个命名变量,它不再是“临时变量”。变成了左值。

因为您知道调用构造函数时值 右值,您可以安全地移动成员,将它们转换回右值。

C(C &&temp)
: mVector(std::move(temp.mVector))
//        ^^^^^^^^^ We know that temp CAME FROM an r-value,
//                  so it can safely be moved.
, mSize(temp.mSize)
{}   

尝试运行以下代码,一切都会变得清晰:

struct Test
{
    Test(){}
    Test(const Test& r)
    {
        std::cout << "i am using the copy constructor :) " << std::endl;
    }
    
    Test(Test&& r)
    {
        std::cout << "I require std::move to be selected as possible overload.." << std::endl;
    }
    
};

int main()
{
    Test first;
    Test second(first);
    
    Test third(std::move(second));
    return 0;
}

std::move 通过将右值引用 (Test&&) 传递给构造函数来帮助 select 正确的构造函数重载。 在您的情况下,即使您的向量不是 const,编译器也会 selecting 复制构造函数,只是因为它被认为是最佳匹配(隐式转换为 const 引用优于隐式转换为 r -value 引用,因为第二个与第一个不同,可能会修改值)添加 std::move 您可以 select 正确的构造函数并解决您的问题。

#include <memory>

struct C
{
    std::unique_ptr<int[]> mVector;
    size_t                 mSize;

    C() = default;

    C(C &&temp)
    : mVector(std::move(temp.mVector))
    , mSize(temp.mSize)
    {}    
};