移动构造函数没有调用析构函数?

4

我的理解是,在调用移动构造函数后,析构函数会在输入上被调用。我决定在代码中测试这一点(见底部),但结果与我预期的不同。使用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_(std::move(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个回答

16
我的理解是移动构造函数调用后,输入对象的析构函数被调用。
你的理解是错误的。与移动语义或C++11无关,析构函数何时被调用没有变化,这里也没有变化-在这种情况下,在main的末尾会调用foo的析构函数。
你的困惑可能源于许多情况下看起来好像在移动构造函数之后立即调用了析构函数。
例如,如果你使用右值创建一个Bar: Bar bar(Foo{});那么Foo的析构函数将在Bar的移动构造函数之后运行。但这不是因为有一个移动构造函数,而是因为临时的Foo对象的生命周期已经结束了。

1
Bar bar(Foo())不会创建一个Bar对象。 - Lightness Races in Orbit
6
基本上,移动构造函数不过是浅复制构造函数吗? - Agrim Pathak
6
@anon 浅复制并从源中删除资源句柄。 - M.M
1
Bar bar((Foo())) 也可以用来避免最令人烦恼的解析 - Nicu Stiurca

5
析构函数在对象的生命周期结束时被调用 - 对于自动存储期对象(例如foo),当它们超出作用域时发生。对于静态存储期对象,这发生在程序退出时。对于临时对象,这可能发生在以下情况下:
  1. 在创建它们的语句结束时 - 在Foo foo = Foo();中,假设没有复制省略,由Foo()创建的临时对象将被销毁。
  2. 当绑定到该临时对象的引用被销毁时 - 在{const Foo& foo = Foo(); doStuff();}中,当作用域结束(})时,临时对象将被销毁。
这些标准都与移动构造函数无关。虽然没有规定,但移动构造函数通常会使被移出的对象处于有效状态。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接