为什么rvalue引用成员需要被声明为const?

3

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

#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 是一个右值引用,它是非 const 的,所以 temp.mVector 应该也是非 const 的,并且应该调用 unique_ptr 的移动构造函数,但实际上它调用了被删除的复制构造函数。请问这里出了什么问题?
2个回答

7
为什么rvalue引用成员会是const? 不要假设它是const。您应该假定unique_ptr(const unique_ptr&)仅仅是可用构造函数中最佳匹配。
因为在构造函数中,temp是一个rvalue引用。 惊喜!它不是r-value引用。 当调用构造函数时,变量temp被绑定到一个rvalue上。现在它是一个有名变量,不再是“临时”的。它已经变成了一个l-value。 既然您知道值在构造函数被调用时是r-value,您可以安全地移动成员,将其转换回r-value。
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)
{}   

2

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

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&&)来帮助选择正确的构造函数重载。 在您的情况下,即使您的vector不是const,编译器也会选择复制构造函数,只因为它被认为是最佳匹配(将隐式转换为const引用优于将隐式转换为右值引用,因为后者与前者不同,可能会修改值),添加std::move可以选择正确的构造函数并解决您的问题。

#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)
    {}    
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接