使用非虚拟析构函数的未定义行为 - 这是一个现实问题吗?

时间:2010-12-23 22:43:27

标签: c++ destructor undefined-behavior

请考虑以下代码:

class A 
{
public:
  A() {}
  ~A() {}
};

class B: public A
{
  B() {}
  ~B() {}
};

A* b = new B;
delete b; // undefined behaviour

我的理解是C ++标准说删除b是未定义的行为 - 即任何都可能发生。但是,在现实世界中,我的经验是~A()总是被调用,并且内存被正确释放。

如果B引入任何具有自己的析构函数的类成员,它们将不会被调用,但我只对上面的简单案例感兴趣,其中使用继承可能修复一个类方法中的错误源代码不可用。

显然,在非平凡的情况下,这不是你想要的,但它至少是一致的。对于显示的代码,您是否了解任何 C ++实现,其中上述情况不会发生?

4 个答案:

答案 0 :(得分:6)

这是C ++标签中一个永无止境的问题:“什么是可预测的未定义行为”。易于自行解决:获取每个 C ++编译器实现,并检查可预测的不可预测性是否仍然有效。然而,这是你必须自己做的事情。

回发你发现的内容,知道这些内容非常有用。只要不可预测的内容具有一致且注释的行为。这使得编写C ++编译器的人很难让任何人关注他的产品。按惯例标准化,使用 lot 未定义行为的语言发生 lot

答案 1 :(得分:3)

据我所知,没有实施的情况并非如此。另一方面,有一个课程,如果你把非POD放入其中,它就会爆炸,这是一种不好的事情,将它描述为一个错误是不合理的。

此外,您的问题标题极具误导性。是的,不调用类的析构函数是严重的现实世界的问题。是的,如果你将输入集限制在一个令人难以置信的少数现实世界类中,那就不是问题了。

答案 2 :(得分:1)

“对于显示的代码”,你很可能找不到一个会起作用的实现。也就是说,如果我们排除考虑各种“调试”实现,这些实现是专门用于捕获此类错误的。

答案 3 :(得分:1)

在非平凡的情况下,B类几乎总是比A大,因为它内部有一个A实例以及B的其他成员。当你引入虚拟成员时,它会变得更糟。

因此,虽然~A会被调用,但很容易看出这种事情会导致内存泄漏。它是未定义的行为,不是因为它可能不会调用~A,这基本上是有保证的,而是通过如何管理内存。