我发现自己在理解5.3.5 $ 5中引用C ++标准的句子时遇到了麻烦:(重点是我的)
如果要删除的对象在删除时具有不完整类类型且完整类具有非平凡的析构函数或释放函数,则行为未定义
我知道删除不完整类型问题已在SO中多次讨论,我可以理解为什么删除不完整的类类型是未定义的行为。这Q&A解释得非常好。
我无法理解的是关于完整类类型的部分。是否意味着删除完整类的对象有一个非平凡的析构函数或解除分配函数是未定义的行为?如果是这样,请提供一些代码,说明它可能导致的未定义行为。
答案 0 :(得分:6)
在相关案例中,未定义行为有两个先决条件:
如果这些条件中的任何一个为假,则没有未定义的行为(至少由于讨论的问题)。
这尤其意味着
删除完整类型的对象是安全的(因为将执行正确的析构函数和/或释放函数)。
通过指向不完整类型的指针删除具有普通析构函数且没有用户定义的释放函数的对象是安全的(因为在没有完整的类型信息的情况下,编译器不会调用析构函数和使用默认的释放函数,它完全匹配通过指向完整类型的指针执行删除时会发生的情况。)
答案 1 :(得分: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;
}
答案 2 :(得分:2)
是否意味着删除一个完整类的对象有一个非平凡的析构函数或一个解除分配函数是未定义的行为?
不,因为那意味着
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
继承自另一个具有非平凡析构函数/解除分配的类,它仍然是未定义的行为。