删除完整的类类型会导致未定义的行为吗?

Could deleting complete class type result in undefined behavior?

本文关键字:未定义 类型 删除      更新时间:2023-10-16

我发现自己在理解以下引用自c++标准5.3.5$5的句子方面有困难:(强调是我的)

如果被删除的对象在删除时具有不完整类类型,并且完整类具有重要析构函数或释放函数,则该行为未定义。

我知道这个删除不完整类型的问题已经在SO中讨论了几次,我可以理解为什么删除不完整类类型是未定义的行为。这个问题解释得很好。

我不明白的是关于完整类类型的部分。这是否意味着删除完整类的对象具有非平凡析构函数或释放函数是未定义的行为?如果是,请给出一些代码来说明它可能导致的未定义行为

在相关情况下,未定义行为有两个先决条件:

  1. 对象通过指向不完整类型的指针被删除;
  2. 被删除对象的完整类具有重要的析构函数或(用户定义的)释放函数。

如果这两个条件中的任何一个为假,则没有未定义的行为(至少由于正在讨论的关注点)。

这特别意味着

  1. 删除complete类型的对象是安全的(因为将执行正确的析构函数和/或释放函数)。

  2. 通过指向不完整类型的指针删除带有普通析构函数且没有用户定义的释放函数的对象是安全的(因为在没有完整类型信息的情况下,编译器不会调用析构函数,而是使用默认的释放函数,这完全符合通过指向完整类型的指针执行删除的情况)。

让我试着用下面的代码来解释我所理解的:

struct Foo;
struct Bar;
Foo* newFoo();
Bar* newBar();
int main()
{
   // Get a pointer to Foo, somehow
   Foo* fp = newFoo();
   // Get a pointer to Bar, somehow
   Bar* bp = newBar();
   // Foo is an incomplete class at this point.
   // This is OK since Foo has a trivial destructor.
   delete fp;
   // Bar is an incomplete class at this point.
   // Not OK since Bar has a non-trivial destructor.
   // This is cause for undefined behavior.
   delete bp;
}
struct Foo {};
struct Bar {
   Bar() { data = new int[10]; }
   ~Bar(){ delete [] data; }
   int* data;
};
Foo* newFoo()
{
   return new Foo;
}
Bar* newBar()
{
   return new Bar;
}

这是否意味着删除一个完整类的对象有一个非平凡的析构函数或一个释放函数是未定义的行为?

不,因为那意味着

class Foo {
public:
    ~Foo() { /*do something*/ };
};

是未定义的行为,而不是这样。

您似乎已经知道,删除具有不完整类类型的对象是未定义行为。问题是,只有当类具有非平凡的析构函数/解分配时,它才是未定义行为

在这种情况下不是未定义行为:

//Foo is forward declared somewhere and destructed
//This is the class definition not available at the point that it is destructed
class Foo {
public:
    //~Foo() = default; 
};

只有在这种情况下才未定义

class Foo {
public:
    ~Foo() { /*do something*/ };
};

请注意,即使Foo具有平凡的析构函数/释放,如果Foo继承自另一个具有非平凡的析构函数/释放的类,它仍然是未定义的行为。