【发布时间】:2015-12-09 14:30:02
【问题描述】:
假设我有两个像这样带有非虚拟析构函数的简单类:
struct A
{
~A() { std::cout << "A destructor" << std::endl; }
}
struct B : A
{
~B() { std::cout << "B destructor" << std::endl; }
}
当B 的实例被析构时,A 的析构函数也会被调用。当我通过A* 类型的指针破坏B 的实例时,将不会调用Bs 析构函数。这是否也算作以调用普通成员函数的方式显式调用析构函数?
struct A
{
~A() { std::cout << "Hello" << std::endl; }
void f() { std::cout << "Hello" << std::endl; }
}
A a;
a.~A(); // case 1
a.f(); // case 2
在这个例子中,除了被调用的函数名之外,这两种情况有什么区别吗?
编辑:考虑与 CRTP 相同的示例:
template <typename C>
struct A
{
~A() { static_cast<C*>(this)->~C(); }
}
struct B : public A<B>
{
~B() { std::cout << "B destructor" << std::endl; }
}
A<B>* a = new B();
delete a;
这会导致未定义的行为或内存泄漏吗?
【问题讨论】:
-
When I destruct an instance of B through a pointer of type A*那么你的程序表现出未定义的行为。 -
a.~A();本身是合法的,但是 a) 它结束了a的生命周期,因此在此之后调用a.f()会表现出未定义的行为,并且 b) 最终a将退出作用域和析构函数将被再次调用——这也表现出未定义的行为。长话短说,虽然可以显式调用析构函数,但这并不是一个好主意。 -
@IgorTandetnik 这是个好主意吗?
-
建议将基类的析构函数定义为虚拟,以防止对象析构函数的这种显式调用。您想要显式调用析构函数的一个可能原因是,如果您想要覆盖删除操作符,或者您想要释放分配有新位置的对象。
-
@AlejandroDíaz 是的。
std::vector之类的人经常这样做。push_backet al 上的新位置,pop_back上的显式销毁
标签: c++ destructor