移动构造函数不调用析构函数?

时间:2014-12-22 23:59:08

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

我的理解是在调用move构造函数之后在输入上调用析构函数。我决定在代码中测试它(见下图),但得到的结果与我的预期不同。我使用std :: unique_ptr得到了相同的结果。

期望值:

1
2
bar constructed
foo destructed //due to move
3
i'm foo
4
[Error?]

实际

1
2
bar constructed
3
i'm foo
4
i'm foo
5
foo destructed
foo destructed

代码:

#include <iostream>

class Foo
{
public:
  ~Foo()
  {
    std::cout << "foo deconstructed" << std::endl;
  }
  void speak()
  {
    std::cout << "i'm foo" << std::endl;
  }
};

class Bar
{
public:
  Bar(Foo&& foo) : foo_(foo)
  {
    std::cout << "bar constructed" << std::endl;
  }
  Foo foo_;
};

int main()
{
  std::cout << "1" << std::endl;
  Foo foo;
  std::cout << "2" << std::endl;
  Bar bar(std::move(foo));
  std::cout << "3" << std::endl;
  bar.foo_.speak();
  std::cout << "4" << std::endl;
  foo.speak();
  std::cout << "5" << std::endl;
  return 0;

}

2 个答案:

答案 0 :(得分:12)

  

我的理解是在调用move构造函数

之后在输入上调用析构函数

您的理解不正确。在调用析构函数时,没有关于移动语义或C ++ 11的更改。这里没有任何改变 - 在这种情况下,foo的析构函数在main结束时被调用。

你的混淆可能源于这样一个事实,即在很多情况下看起来似乎是在移动构造函数之后立即调用析构函数。

例如,如果您要创建一个带有右值的BarBar bar(Foo{});Foo的析构函数将在Bar的移动构造函数后运行。这不是因为它有一个移动构造函数 - 它是因为临时Foo对象的生命周期已经结束。

答案 1 :(得分:5)

析构函数在其生命周期结束时被调用 - 对于自动存储持续时间对象,如foo,当它们超出范围时会发生这种情况。对于静态存储持续时间对象,当程序退出时会发生这种情况。对于临时工,这种情况要么发生了

  1. 在创建它们的语句的末尾 - 在Foo foo = Foo();中,假设没有复制省略,Foo()创建的临时文件将被销毁。
  2. 当此临时绑定的引用被销毁时 - 在{const Foo& foo = Foo(); doStuff();}中,当范围结束时(})临时被销毁。
  3. 这些标准都与移动构造函数无关。虽然没有强制要求,但移动构造函数通常会将移出的对象保留在有效状态。