在指针成员之前调用非指针成员的析构函数

Calling destructor of non-pointer member before pointer member

考虑三个 类 这样的:

class A {
    int bar;
};

class B {
    A* a;
public:
    B(*A na)
    : a(na)
    {}

    ~B() {
        a->bar = 0;
    }
};

class Foo {
    A* a;
    B b;
public:
    Foo()
    : a(new A)
    , b(a)
    {}

    ~Foo() {
        delete a;
    }
};

创建 Foo 的实例,导致 Foo 具有指向 A 的指针,B 具有相同的指针。

Foo的实例被删除时,指针a被删除,然后调用b的析构函数,但是~B试图访问a,已在 ~Foo 中释放,导致分段错误。

有没有办法在 ~Foo 的 运行 主体之前调用 b 的析构函数?

我知道我可以通过将 b 设为指针或将 a 设为非指针来解决此问题。如果 A 是抽象的,则后者不起作用,我想知道是否可以不使 b 成为指针。

PS: AB 都来自库,所以我无法更改它们的实现。

编辑:更正错误(感谢@Yakk)

您需要将 B 设为 Foo 中的指针,以便您可以控制析构函数中的删除顺序,或者将 A 设为非指针并将其定位在 [= 之前10=] 在 Foo 的成员顺序中,以便它在 B 之后被销毁,但这会使代码变得脆弱,因为成员声明的顺序现在很重要。在您的代码中对此进行注释。

创造一个中间体class。

 class PreFoo 
 {
   A* a:
    ...
 };

 class Foo : public PreFoo
 {
   B b;
   ...
 };

遵循 RAII 原则。

Foo::a 更改为 std::unique_ptr<A>。从 ~Foo.

中删除 delete

现在将在~Foo结束后和b.~Bar()后销毁。

注意成员是按照声明的顺序创建的,按照相反的顺序销毁。 (令人惊讶的是,初始化列表中的顺序不会改变创建顺序)。所以如果你想让 a 活得比 b 长,只需先声明它即可。