【问题标题】:Move constructor not calling destructor?移动构造函数不调用析构函数?
【发布时间】:2015-02-21 02:51:22
【问题描述】:

我的理解是在调用移动构造函数之后在输入上调用析构函数。我决定在代码中对此进行测试(见底部),但得到的结果与我的预期不同。我使用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;
}

【问题讨论】:

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


    【解决方案1】:

    我的理解是在调用move构造函数之后在输入上调用析构函数

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

    您的困惑可能源于这样一个事实,即在许多情况下,析构函数似乎是在移动构造函数之后立即调用的。

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

    【讨论】:

    • Bar bar(Foo()) 不会创建 Bar
    • 所以基本上一个移动构造函数只不过是浅拷贝构造函数?
    • @anon shallow-copy 并从源中删除资源句柄
    • Bar bar((Foo())) 也可以用来避免the most vexing parse
    【解决方案2】:

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

    1. 在创建它们的语句末尾 - 在 Foo foo = Foo(); 中,假设没有复制省略,由 Foo() 创建的临时对象被销毁。
    2. 当此临时绑定到的引用被销毁 - 在 {const Foo&amp; foo = Foo(); doStuff();} 中,临时在范围结束时被销毁 (})。

    这些条件都与移动构造函数无关。虽然没有强制要求,但移动构造函数通常会使被移出的对象保持有效状态。

    【讨论】:

      猜你喜欢
      • 2011-05-22
      • 2011-04-16
      • 1970-01-01
      • 2015-06-30
      • 2022-11-21
      • 2017-11-03
      • 1970-01-01
      • 2015-06-27
      • 1970-01-01
      相关资源
      最近更新 更多