非虚拟析构函数的未定义行为 - 这是现实世界的问题吗?
考虑下面的代码:
class A
{
public:
A() {}
~A() {}
};
class B: public A
{
B() {}
~B() {}
};
A* b = new B;
delete b; // undefined behaviour
我的理解是,C++ 标准说删除 b 是未定义的行为 - 即,任何事情都可能发生。但是,在现实世界中,我的经验是〜A()总是被调用,并且内存被正确释放。
如果 B 引入任何具有自己的析构函数的类成员,它们将不会被调用,但我只对上面的简单情况感兴趣,其中继承可能用于修复源代码为的一个类方法中的错误不可用。
显然,在重要的情况下这不会是您想要的,但它至少是一致的。对于所示的代码,您是否知道有任何 C++ 实现不会发生上述情况?
Consider the following code:
class A
{
public:
A() {}
~A() {}
};
class B: public A
{
B() {}
~B() {}
};
A* b = new B;
delete b; // undefined behaviour
My understanding is that the C++ standard says that deleting b is undefined behaviour - ie, anything could happen. But, in the real world, my experience is that ~A() is always invoked, and the memory is correctly freed.
if B introduces any class members with their own destructors, they won't get invoked, but I'm only interested in the simple kind of case above, where inheritance is used maybe to fix a bug in one class method for which source code is unavailable.
Obviously this isn't going to be what you want in non-trivial cases, but it is at least consistent. Are you aware of any C++ implementation where the above does NOT happen, for the code shown?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这是C++标签中一个永无止境的问题:“什么是可预测的未定义行为”。很容易自己解决所有问题:获取每个 C++ 编译器实现并检查可预测的不可预测的内容是否仍然有效。然而,这是您必须自己做的事情。
请发回您发现的内容,这将非常有用。只要不可预测的事物具有全面一致且带注释的行为。对于编写 C++ 编译器的人来说,很难让任何人关注他的产品。按照惯例,标准化会在具有大量未定义行为的语言中发生。
This is a never-ending question in the C++ tag: "What is the predictable undefined behavior". Easy to resolve all by yourself: get every C++ compiler implementation and check if the predictable unpredictable still works. This is however something you have to do by yourself.
Do post back what you found out, that would be quite useful to know. As long as the unpredictable has consistent and annotated behavior across the board. It makes it really hard for somebody that writes a C++ compiler to get anybody to pay attention to his product. Standardization by convention, happens a lot with a language that has a lot of undefined behavior.
据我所知,没有任何实施是不正确的。另一方面,如果你在一个类中放入一个非 POD,它就会爆炸,这是一种糟糕的事情,将其描述为错误几乎没有道理。
另外,你的问题标题非常具有误导性。是的,不调用类的析构函数是一个严重的现实问题。是的,如果您将输入集限制为现实世界中极少数的类,那么这不是问题。
As far as I know, there's no implementation where that's not true. On the other hand, having a class where if you put a non-POD in it, it blows up, is the kind of bad thing that it's hardly unreasonable to describe as a bug.
In addition, your question title is incredibly misleading. Yes, it is a serious real world problem to not invoke a class's destructor. Yes, if you restrict the input set to an incredible minority of real world classes, it's not a problem.
在重要情况下,B 类几乎总是比 A 类大,因为它内部有 A 类的实例以及 B 类的附加成员。当引入虚拟成员时,情况会变得更糟。
因此,虽然 ~A 会被调用,但很容易看出这种事情可能会导致内存泄漏。这是未定义的行为,不是因为它可能不会调用 ~A(这基本上是可以保证的),而是因为内存的管理方式。
Class B will almost always be larger than A in non-trivial cases, because it has an instance of A inside it as well as the additional members of B. It gets worse when you introduce virtual members.
So while ~A will get called, it is easy to see that this kind of thing can result in a memory leak. It is undefined behaviour not because it may not call ~A, that is basically guaranteed, but by how the memory is managed.
“对于所示的代码”,您不太可能找到能够正常运行的实现。也就是说,如果我们不考虑各种“调试”实现,这些实现是专门为捕获此类错误而设计的。
"For the code shown" it is very unlikely you'll ever find an implementation that will act up. That is if we exclude from consideration various "debugging" implementations, which are specifically and intentionally designed to catch such errors.