虚拟析构函数和未定义的行为 [英] Virtual destructor and undefined behavior

查看:95
本文介绍了虚拟析构函数和未定义的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题与'不同。


$

b $ b

  struct B {
virtual void foo();
〜B(){} //< --- not virtual
};
struct D:B {
virtual void foo();
〜D(){}
};
B * p = new D;
delete p; // D ::〜D()不叫

问题


  1. 这可以归类为未定义的行为(我们知道〜D()

  2. 如果〜D()空。 c> / 删除[] code>与 B * p; 〜D()肯定不会
    get调用,而不管析构函数的 virtual ness。是否
    是未定义的行为或明确定义的行为?


解决方案

何时/为什么要使用虚拟析构函数?

按照Herb Sutters 指南


基类析构函数应该是public和virtual,

这可以归类为未定义的行为(我们知道〜D()不会被调用)?



它是未定义的行为根据标准,这通常导致Derived类析构函数不被调用,导致内存泄漏,但它是无关的



C ++ 03标准:5.3.5删除



5.3.5 / 1:


delete-expression运算符销毁由new-expression创建的最多派生对象(1.8)或数组。

delete-expression:

:: opt delete cast-expression

:: opt delete [] cast-expression


5.3.5 / 3:



在第一个选项(删除对象)中,如果操作数的静态类型与其动态类型不同,类型应为操作数动态类型的基类,静态类型应具有虚拟析构函数或行为未定义。在第二个选项(删除数组)中,如果要删除的对象的动态类型与它的静态类型,行为是undefined的。)


如果〜D / code>为空。它会以任何方式影响代码吗?

仍然是未定义行为按照标准,派生类析构函数为空可能只是使你的程序工作正常,但这是再次实现定义方面的技术上,它仍然是一个未定义的行为。



请注意,这里没有gvernee,不使派生类析构函数virtual不会导致调用派生类析构函数,这个假设是不正确的。根据标准,一旦你在未定义的行为土地中交叉,所有的赌注都会关闭。



注意他的标准对未定义行为的描述。



C ++ 03标准:1.3.12未定义行为[defns.undefined]




例如在使用错误的程序结构或错误的数据时可能出现的行为,本国际标准对该行为没有要求。当本国际标准省略对行为的任何明确定义的描述时,也可以预期未定义的行为。 [注意:允许的未定义行为的范围包括完全忽略具有不可预测的结果的情况,在以
翻译或程序执行期间以记录的环境特征(有或没有发出诊断消息)以终止翻译或执行(通过发出诊断消息)。许多错误的程序结构不会产生未定义的行为;
]


如果只有衍生析构函数不会被调用,上面的引用,这显然留给每个实现。


This question is different than 'When/why should I use a virtual destructor?'.

struct B {
  virtual void foo ();
  ~B() {}  // <--- not virtual
};
struct D : B {
  virtual void foo ();
  ~D() {}
};
B *p = new D;
delete p;  // D::~D() is not called

Questions:

  1. Can this be classified as an undefined behavior (we are aware that ~D() is not going to be called for sure)?
  2. What if ~D() is empty. Will it affect the code in any way?
  3. Upon using new[]/delete[] with B* p;, the ~D() will certainly not get called, irrespective of virtualness of the destructor. Is it an undefined behavior or well defined behavior?

解决方案

when/why should I use a virtual destructor?
Follow Herb Sutters guideline:

A base class destructor should be either public and virtual, or protected and nonvirtual

Can this be classified as an undefined behavior (we are aware that ~D() is not going to be called for sure) ?

It is Undefined Behavior as per the standard, which usually results in the Derived class destructor not being called and resulting in a memory leak, but it is irrelevant to speculate on after effetcs of an Undefined Behavior because standard doesn't gaurantee anything in this regard.

C++03 Standard: 5.3.5 Delete

5.3.5/1:

The delete-expression operator destroys a most derived object (1.8) or array created by a new-expression.
delete-expression:
::opt delete cast-expression
::opt delete [ ] cast-expression

5.3.5/3:

In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined. In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.73)

What if ~D() is empty. Will it affect the code in any way ?
Still it is Undefined Behavior as per the standard, The derived class destructor being empty may just make your program work normally but that is again implementation defined aspect of an particular implementation, technically, it is still an Undefined Behavior.

Note that there is no gaurantee here that not making the derived class destructor virtual just does not result in call to derived class destructor and this assumption is incorrect. As per the Standard all bets are off once you are crossed over in Undefined Behavior land.

Note what he standard says about Undefined Behavior.

The C++03 Standard: 1.3.12 undefined behavior [defns.undefined]

behavior, such as might arise upon use of an erroneous program construct or erroneous data, for which this International Standard imposes no requirements. Undefined behavior may also be expected when this International Standard omits the description of any explicit definition of behavior. [Note: permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). Many erroneous program constructs do not engender undefined behavior; they are required to be diagnosed. ]

If only derived destructor will be not called is governed by the bold text in the above quote, which is clearly left open for each implementation.

这篇关于虚拟析构函数和未定义的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆