如果从析构函数调用纯虚函数是UB,为什么我们可以使用纯虚拟desrtuctors?

时间:2014-06-15 11:28:42

标签: c++ destructor undefined-behavior pure-virtual

众所周知,我们可以使用纯虚拟析构函数,如下所示:

struct A {
    virtual ~A() = 0;
};
A::~A() {}

struct B : A {};

因为标准在10.4 [class.abstract] p2

中说明
  

只有在调用...(12.4 [class.dtor])

时才需要定义纯虚函数

后来在12.4 [class.dtor] p9

  

析构函数可以声明为虚拟(10.3)或纯虚拟(10.4);如果在程序中创建了该类或任何派生类的任何对象,则应定义析构函数。

上述代码完全有效意味着什么 - A::~A可能是纯虚拟的,已定义,B::~B隐式调用A::~A

到目前为止,非常好 然后我读了10.4 [class.abstract] p6

  

可以从抽象类的构造函数(或析构函数)调用成员函数;对于从这样的构造函数(或析构函数)创建(或销毁)的对象,直接或间接地对纯虚函数进行虚拟调用(10.3)的效​​果是未定义的。

但这正是我们在这里所做的 - 我们从析构函数中调用纯虚函数A::~A

那么,是不是存在某种矛盾?

2 个答案:

答案 0 :(得分:3)

没有收缩。

您从A的析构函数调用B的虚拟析构函数。A析构函数不是B的成员。

标准§9.3

会员职能

  

在类的定义中声明的函数,不包括那些   用朋友说明者宣布(   11.3),被称为该类的成员函数

标准声明当从抽象类析构函数/构造函数(在您的情况下,将为类A)中的虚拟调用到其中一个时,存在未定义的行为拥有纯虚拟成员函数。

  

[...]可以从抽象类[...]的构造函数(或析构函数)调用成员函数;

你的引言是针对析构函数的:

  1. 您可以从抽象类的析构函数中调用成员函数
  2. 如果从同一抽象类的析构函数中调用纯虚方法(带虚拟调用) ,则存在未定义的行为。

答案 1 :(得分:-2)

如果存在虚拟呼叫(10.3 [class.virtual]),则会发生UB。

  

对纯虚函数进行虚拟调用(10.3)的效​​果是未定义的。

但10.3 [class.virtual] p15表示

  

使用范围运算符(5.1)进行显式限定可以抑制虚拟调用机制。

似乎隐式析构函数调用具有明确的限定条件 至少编译器肯定不会在那里进行虚拟调用。