【问题标题】:Understanding move constructor, std::move, and destructor了解移动构造函数、std::move 和析构函数
【发布时间】:2014-03-13 02:07:24
【问题描述】:

我是 c++11 的新手,写了以下代码来了解 std::move 的工作原理:

#include <queue>
#include <stdio.h>

class X {
 public:
  X(int x) : x_(x) {}
  ~X() {
    printf("X(%d) has be released.\n", x_);
  }

  X(X&&) = default;
  X& operator = (X&&) = default;

  X(const X&) = delete;
  X& operator = (const X&) = delete;
 private:
  int x_;
};


int main() {
  std::queue<X> xqueue;
  for (int x = 0; x < 5; ++x) {
    xqueue.push(std::move(X(x)));
  }
  return 0;
}

但是,它会生成以下输出,这表明每个X(n) 的析构函数都被调用了两次:

X(0) has be released.
X(1) has be released.
X(2) has be released.
X(3) has be released.
X(4) has be released.
X(0) has be released.
X(1) has be released.
X(2) has be released.
X(3) has be released.
X(4) has be released.

我可以想象第二轮输出发生在 main() 函数的末尾,而第一轮可能发生在循环中,当那些中间 Xs 超出范围时。

但是,我认为这样的中间Xs 的所有权将被完美地转移到队列中,并且在所有权转移期间不应调用它们的析构函数。

所以我的问题是:

  1. 当我看到一个实例被释放两次时,这是否意味着它执行的是复制而不是移动?
  2. 如果上面的答案是肯定的,那我怎样才能真正避免抄袭呢?

谢谢,

【问题讨论】:

    标签: c++ c++11 destructor move


    【解决方案1】:

    如果你从一个对象移动到另一个对象,你仍然有两个对象。他们都需要被摧毁。也许move 是一个有点误导性的术语,但从一个地方移动到另一个地方的并不是对象本身(对象实际上从不移动)——而是对象的内容。

    1. 没有。如上所述,移动不会消失其中一个对象。从一个对象到另一个对象的复制和移动都将涉及两个对象。不同之处在于它们对对象的影响。副本当然会将一个对象的成员复制到另一个对象。另一方面,移动会将成员从一个对象移动到另一个对象 - 通常是更快的操作。
    2. 不适用

    【讨论】:

    • 所以如果我的对象有成员指针,它的析构函数就会释放这些指针。这是否意味着我不能真正移动这些对象?
    • @keelar 你可以——当你离开它时,只需将指针设置为nullptr。对空指针执行delete 将无效。当您实现移动构造函数/赋值运算符时,您应该让对象处于有效(但不确定)状态。
    • 非常感谢!这听起来很完美。我能否进一步知道= default 移动构造函数/赋值是否会将nullptr 分配给源成员指针?还是我应该开发自己的移动构造函数/赋值?
    • @keelar 如果您的类正在执行内存管理,那么您肯定需要自己实现移动构造函数/赋值运算符。隐式定义的移动构造函数只会对其每个成员执行移动(如,它将从旧对象的成员中移动构造新对象的成员)。这被称为rule of five。但是,如果您关注rule of zero,您通常可以避免这样做。
    【解决方案2】:

    移动构造函数窃取对象的属性/成员并将其提供给新对象。因此,在您的示例中,当移动构造函数的范围结束并且现在 empty 对象被销毁时,会发生第一组删除语句。

    而第二组delete语句发生在队列中新创建的对象被销毁时

    另外值得注意的是,如果被删除对象的属性不是POD类型,那么在delete方法中访问它们不是一个好主意,否则会导致seg错误

    【讨论】:

      猜你喜欢
      • 2015-02-14
      • 2013-12-08
      • 1970-01-01
      • 1970-01-01
      • 2014-05-02
      • 1970-01-01
      • 2013-01-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多