移动链接到构造函数的方法的语义

Move semantics of a method chained to a constructor

我是 C++ 新手,正在尝试掌握移动语义。以下代码是我编写的准系统结构。无论如何,它都不是软件工程的最佳示例,但仅供学习之用。它拥有一个资源,删除了复制构造函数和复制赋值运算符,定义了一个移动构造函数和一个移动赋值运算符,有一个析构函数,并且有一个应该 return 原始对象的方法:

struct HasAResource
{
    int* arr;

    HasAResource(int size):
        arr(new int [size])
    {}

    HasAResource(const HasAResource& other) = delete;
    HasAResource& operator=(const HasAResource& other) = delete;

    HasAResource(HasAResource&& other):
        arr(nullptr)
    {
        arr = other.arr;
        other.arr = nullptr;
    }

    HasAResource& operator=(HasAResource&& other)
    {
        if (this != &other)
        {
            delete[] arr;
            arr = other.arr;
            other.arr = nullptr;
        }
        return *this;
    }

    ~HasAResource() { delete[] arr; }

    HasAResource& doStuff()
    {
        return *this;
    }
};

int main(int argc, char const *argv[])
{
    HasAResource x = HasAResource(42).doStuff();
    return 0;
}

在主函数中,我试图构造一个对象并立即调用它的方法。我的目标是修改我构建的临时对象,然后他们将其移动到 x 而不制作任何副本(这样资源只有一个所有者)。但是,编译器给我一个与删除的复制构造函数相关的错误。这意味着尽管我尽了最大努力,它仍在尝试制作副本。

我的问题是:

  1. 这里到底发生了什么?新对象在哪里是右值或左值,为什么?
  2. 如果可能,我如何修改此程序以实现所需的行为?

再次强调,我的目标是了解语言在做什么,而不是最佳软件工程实践(比如使用std::unique_ptr)。

My goal was to modify the temporary object I constructed and them move it to x without making any copies

doStuff() 不会 return 成为 临时 ,因此 x 没有可移动的右值。由于 doStuff() 的 return 值不是右值,编译器无法调用 x 的移动构造函数,因此它尝试调用复制构造函数并因此失败的原因是那就是delete

在这种情况下,您将需要使用 std::move() 显式将 returned 引用转换为右值,然后移动构造函数将按预期调用:

HasAResource x = std::move(HasAResource(42).doStuff());

Demo

否则,按值将doStuff()更改为return一个新对象,并让编译器使用copy elision为您优化临时对象,例如:

static HasAResource doStuff(int size)
{
    HasAResource x(size);
    x.doStuff();
    return x;
}

HasAResource x = HasAResource::doStuff(42);

Demo