在指针成员之前调用非指针成员的析构函数
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: A
和 B
都来自库,所以我无法更改它们的实现。
编辑:更正错误(感谢@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
长,只需先声明它即可。
考虑三个 类 这样的:
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: A
和 B
都来自库,所以我无法更改它们的实现。
编辑:更正错误(感谢@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
长,只需先声明它即可。