【问题标题】:Move semantics of a method chained to a constructor移动链接到构造函数的方法的语义
【发布时间】:2021-05-04 23:23:50
【问题描述】:

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

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)。

【问题讨论】:

  • HasAResource x = (expression that evaluates to HasAResource&) 你希望它使用什么操作,为什么?
  • 好吧,我不是专家,但您似乎是通过引用新对象的构造函数来传递临时值。这意味着一个复制构造函数。您可以按值传递,即使用 rvo 或尝试使用 std::move 强制转换为右值引用。

标签: c++ constructor move-semantics


【解决方案1】:

我的目标是修改我构建的临时对象,然后他们将其移动到 x 而不制作任何副本

doStuff() 不返回 临时,因此x 没有右值可以移动。由于doStuff() 的返回值不是右值,因此编译器无法调用x 的移动构造函数,因此它尝试调用复制构造函数并因此由于delete'd 而失败。

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

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

Demo

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

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

HasAResource x = HasAResource::doStuff(42);

Demo

【讨论】:

  • HasAResource&& doStuff() &&; 是另一种选择
猜你喜欢
  • 1970-01-01
  • 2018-05-08
  • 1970-01-01
  • 2013-11-05
  • 1970-01-01
  • 1970-01-01
  • 2021-12-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多