【问题标题】:Delete objects of incomplete type删除不完整类型的对象
【发布时间】:2011-05-18 12:44:53
【问题描述】:

这个让我想到:

class X;

void foo(X* p)
{
    delete p;
}

如果我们甚至不知道X 是否有可见的析构函数,我们怎么可能delete p? g++ 4.5.1 给出三个警告:

warning: possible problem detected in invocation of delete operator:
warning: 'p' has incomplete type
warning: forward declaration of 'struct X'

然后它说:

注意:既不是析构函数也不是特定于类的操作符 delete 将被调用,即使它们是在定义类时声明的。

哇...是否需要编译器来像 g++ 那样诊断这种情况?还是未定义的行为?

【问题讨论】:

标签: c++ pointers forward-declaration delete-operator incomplete-type


【解决方案1】:

来自标准的[expr.delete]:

如果被删除的对象有 不完整的类类型 删除和完整的类有一个 非平凡的析构函数或 释放函数,行为是 未定义。

所以,如果有重要的事情要做,那就是 UB,如果没有也没关系。 UB 不需要警告。

【讨论】:

  • 不,不是“UB if”,而是无条件的 UB。例如,该类可以在单独的堆上重载 operator new,而 delete 语句现在将调用错误的 operator delete
  • 我删除了模棱两可的部分。据我所见,标准并没有说删除不完整类型的对象在每种情况下都是 UB,正如我在引用的部分中提到的那样。为什么你认为它是无条件的UB? (标准在哪里这么说的?)
  • @etarion:标准规定行为将取决于该类的声明方式,这意味着您可以从满足这些要求的类开始,然后将其更改为不满足这些要求,现在您将面临 UB (顺便说一句,这可以是“它有效”)。因此,尽管您在形式上是干净的,但您已经在代码中植入了一个致命错误。应该解决有问题的警告 - deleteing 不完整的课程是一个非常糟糕的主意。
  • 所以它实际上是有条件的 UB,而不是你声称的无条件。 (我不是在争论这是否是好的做法。OP 中的问题是是否需要诊断 - 否 - 如果是 UB - 这取决于。)
  • 如果您取消“非平凡”位,我会为这个答案 +1。这是完全正确的——你可以删除不完整类型的“东西”,只要最终完成该类型的人确保它具有微不足道的破坏和释放。希望这将被记录在某个地方,或者也许那个“谁”是你。将空指针传递给前向声明的函数不再是“无条件 UB”,而是“无条件 UB”。毕竟,函数可以取消引用它。但是如果文档说没有,那你就没事。或者至少,如果是这样,那是别人的错……
【解决方案2】:

这是未定义的行为。

但是,您可以让编译器检查不完整的类型,例如 boost:

// verify that types are complete for increased safety

template<class T> inline void checked_delete(T * x)
{
    // intentionally complex - simplification causes regressions
    typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
    (void) sizeof(type_must_be_complete);
    delete x;
}

sizeof 应用于不完整的类型应该会触发错误,我想如果通过某些编译器通过,那么负大小的数组会触发错误。

【讨论】:

    【解决方案3】:

    这是未定义的行为,也是实现 pImpl 模式时的常见问题。据我所知,根本没有编译器需要发出警告之类的东西。警告是可选的;它们在那里是因为编译器编写者认为它们会很有用。

    【讨论】:

      猜你喜欢
      • 2012-08-19
      • 2019-07-29
      • 2018-01-02
      • 2016-12-29
      • 2015-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多