在不完整类型的空指针上调用 delete 是否合法?

Is it legal to call delete on a null pointer of an incomplete type?

如果是这样,为什么下面的代码会给我警告

note: neither the destructor nor the class-specific operator delete will be called, even if they are declared when the class is defined

?

struct C;

int main()
{
    C *c = nullptr;

    delete c;

    return 0;
}

理解为什么如果C有non-trivial/virtual析构函数,在一般情况下可能是未定义的行为, 但标准 guarantee/define nullptr 上的 delete 是否总是 noop 无论情况如何?

重申一下:我特别询问指向不完整类型的指针是 nullptr!

的情况

标准说 ([expr.delete]/5):

If the object being deleted has incomplete class type at the point of deletion and the complete class has a non-trivial destructor or a deallocation function, the behavior is undefined.

因此,如果 T 具有非平凡的析构函数或具有 operator delete 重载,您将获得 UB。关于 UB 基于指针的 value(即:它是否为空指针)没有任何说明。


"object being deleted" 是什么意思?

可以认为 "object being deleted" 意味着该子句仅适用于对实际对象的 delete 调用。因此,如果您传递一个空指针,它不适用。

首先,关于 delete 行为的其余标准讨论明确指出其行为不适用于空指针。 [expr.delete]/6&7 均以 "If the value of the operand of the delete-expression is not a null pointer value" 开头。第 5 段 明确地 不包含这些词。因此,我们必须假设它确实适用于空指针。

其次,如果给"object being deleted"传递一个空指针,它的含义是什么?毕竟那里没有"object"

好吧,如果 "object being deleted" 专门讨论该指针末尾的对象,请考虑解释此文本的含义。好吧,如果您要删除具有非平凡析构函数的不完整 classes 数组,会发生什么情况?

根据该逻辑,此子句不适用,无论指针是否为空。为什么?因为 "object being deleted" 是 array 类型,而不是 class 类型。因此,该条款不能适用。这意味着编译器必须能够在不完整的 classes.

数组上调用 delete[]

但这不可能实施;它将要求编译器能够追踪尚不存在的代码。

因此,要么 "object being deleted" 打算 引用 std::remove_pointer_t<std::decay_t<decltype(expr)>>,要么标准要求的行为无法实现。标准措辞可能会稍微清理一下,将 "If the object being deleted has incomplete class type at the point of deletion" 替换为 "If T is a pointer to U or an array of U, and U has incomplete class type at the point of deletion, ..."