重置移动对象的常用习语是什么?

What is the common idiom(s) for resetting the moved object?

在 C++ 中,需要移动构造函数来重置移动的对象,这对我来说似乎是大多数情况下析构函数的重复。

定义重置方法并在析构函数和移动构造函数中使用它是最好的方法是否正确?或者也许有更好的方法?

移动构造函数通常会“窃取”参数持有的资源(例如指向 dynamically-allocated 对象、文件描述符、TCP 套接字、I/O 流、运行 线程等的指针。 ) 而不是制作它们的副本,并将论证保留在某个有效但不确定的状态。对于某些类型,例如 std::unique_ptr,moved-from 状态已完全指定。

不应释放“被盗”资源,因为这通常会导致错误。例如,“窃取”指针的移动构造函数必须确保 moved-from 对象的析构函数不会 delete 指针。否则会有一个double-free。一种常见的实现方式是将 moved-from 指针重置为 nullptr.

这是一个例子:

struct Pointer {
    int *ptr;

    // obtain a ptr resource which we will manage
    Pointer(int* ptr) : ptr{ptr} {}

    // steal another object's ptr resource, assign it to nullptr
    Pointer(Pointer &&moveOf) : ptr{moveOf.ptr} {
        moveOf.ptr = nullptr;
    }

    // make sure that we don't delete a stolen ptr
    ~Pointer() {
        if (ptr != nullptr) {
            delete ptr;
        }
    }
};

Is it correct that defining a reset-method and using it in both destructor and move-constructor is the best approach? Or maybe there are better ways?

这取决于所管理的资源,但通常析构函数和 move-constructor 做不同的事情。移动构造函数窃取资源,析构函数释放未被窃取的资源。

In C++ move constructor is required to reset the moved object which to me seems to be a duplication of what the destructor does in most of the cases.

你是对的,经常有重复工作。这是因为 C++ 没有破坏性的移动语义,所以析构函数仍然会单独调用,即使对象已被移动。在我展示的示例中,~Pointer() 仍然需要被调用,即使是在移动之后。这伴随着检查是否 ptr == nullptr 的运行时成本。具有破坏性移动语义的语言示例 .


相关帖子:

  • How to define a move constructor?

is required to reset the moved object which to me seems to be a duplication of what the destructor does in most of the cases.

在我看来,您误解了析构函数在大多数情况下的用途。

move中“reset”(如你所说)的目的是设置对象的状态,使其满足析构函数的内部pre-conditions(更一般地说,任何class不变)。如果构造函数不这样做,那么对象就不能被销毁,这将违反约定和良好做法,并可能导致错误。

在许多情况下,析构函数不可能进行同样的“重置”。例如,无法区分无效指针和有效指针。这就是智能指针的移动构造函数将指针重置为空的原因。

Is it correct that defining a reset-method and using it in both destructor and move-constructor is the best approach?

尚不清楚这何时有用。看起来不典型。