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

If call to a pure virtual function from destructor is UB, why can we use pure virtual desrtuctors?

本文关键字:为什么 可以使 析构函数 析构 函数调用 函数 如果 UB      更新时间:2023-10-16

可以使用纯虚析构函数,如下所示:

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

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

纯虚函数只有在调用时才需要定义…With (12.4 [class. doctor])

之后在12.4 [class.dtor] p9

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

这意味着上面的代码是完全有效的——A::~A可能是纯虚的,它是定义的,B::~B隐式调用A::~A

到目前为止,一切顺利。
然后我读到10.4 [class.abstract] p6:

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

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

所以,这不是某种矛盾吗?

没有收缩

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

标准§9.3

成员函数

在类定义中声明的函数,不包括那些用友元说明符声明(

类的成员函数

标准规定,当从抽象类析构函数/构造函数(在您的例子中,将是类A)向其自己的纯虚成员函数之一进行虚调用时,存在未定义的行为。

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

你的引言说对于析构函数:

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

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

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

但10.3[类。虚拟]p15说

作用域操作符(5.1)的显式限定抑制了虚调用机制。

似乎隐式析构函数调用具有显式限定条件。
至少编译器不会做虚调用