理解移动构造函数,std :: move和析构函数

时间:2014-02-13 22:37:10

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

我是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()函数的末尾,第一轮可能发生在循环中,当那些中间X超出范围时。

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

所以我的问题是:

  1. 当我看到一个实例被解除分配两次时,这是否意味着它执行复制而不是移动?
  2. 如果上述答案是肯定的,那么我该如何避免复制呢?
  3. 谢谢,

2 个答案:

答案 0 :(得分:5)

如果从一个对象移动到另一个对象,则总共还有两个对象。它们都需要被摧毁。也许move是一个有点误导性的术语,但不是对象本身从一个地方移动到另一个地方(物体从未实际移动) - 它是对象的内容。

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

答案 1 :(得分:1)

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

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

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