在 C++ 的析构函数中允许做什么?

What is allowed to do in destructors in C++?

我正在尝试了解在析构函数中允许做什么。

standard 说:“对于具有非平凡析构函数的对象,在析构函数完成执行后引用对象的任何非静态成员或基 class 会导致未定义的行为".
cppreference 这样描述析构序列:“对于用户定义的或隐式定义的析构函数,在执行析构函数体后,编译器会为 [= 的所有非静态非变体成员调用析构函数23=]".

这是否意味着,在下面的代码中,从其成员的析构函数中调用方法是UB?或者通过“参考”标准来表示特定的东西?

struct Foo {
  Foo(Callback cb) : cb_(cb) {}

  ~Foo() {
    // body of Bar destructor finished at this moment;
    // cb_() calls Bar::call_me()
    cb_();
  }

  Callback cb_;
};

struct Bar {
  // pass callback with captured this
  Bar() : foo_([this]() { call_me(); }) {
  }

  void call_me() {
  }

  // foo is a member, its destructor will be called after Bar destructor
  Foo foo_;
};

此外,标准中的短语“析构函数完成后”究竟是什么意思?在析构函数的主体完成之后?或者在所有成员和基地 classes 被摧毁之后?
我认为最后一个问题的答案是理解什么是允许的,什么不是的关键。

Bar的析构函数还没有结束,所以引用Bar的一个成员,确实可以在其析构函数中调用Bar的成员函数。

虽然调用超对象的成员函数可能有点不稳定,因为成员函数可能访问子对象,而一些子对象可能在调用成员函数时已经被销毁,在这种情况下访问被破坏的对象会导致未定义的行为。在您的示例中不是这种情况。

Or by "referring" standard means something particular?

我觉得是形成一个指针或者指向子对象的引用。正如规则下方示例中所做的那样。


Also, what does the phrase "after the destructor finishes" from the standard mean exactly? After the body of a destructor finishes? Or after all members and base classes destroyed?

后者。

先执行主体,然后析构函数调用子对象析构函数,然后析构函数完成。