Zeb*_*ish 3 c++ undefined-behavior language-lawyer
我想知道以下是否未定义?
int main()
{
struct Doggy { int a; ~Doggy() {} };
Doggy* p = new Doggy[100];
p[50].~Doggy();
p[50].a = 3; // Is this not allowed? The destructor was called on an
// object occupying that area of memory.
// Can I access it safely?
if (p[50].a == 3);
}
Run Code Online (Sandbox Code Playgroud)
我想这通常很好知道,但我特别想知道的原因是我有一个由数组组成的数据结构,其中存储桶可以通过设置一个值来为空,有点像哈希表中的存储桶大批。当桶被清空时,析构函数被调用,但是在调用析构函数之后检查和设置空状态我想知道它是否非法。
详细说明一下,假设我有一个对象数组,并且每个对象都可以表示每个存储桶中的空值,例如:
struct Handle
{
int value = 0; // Zero is null value
~Handle(){}
};
int main()
{
Handle* p = new Handle[100];
// Remove object 50
p[50].~Handle();
p[50].value = 0; // Set to null
if (p[50].value == 0) ; // Then it's null, can I count on this?
// Is this defined? I'm accessing memory that was occupied by
// object that was destroyed.
}
Run Code Online (Sandbox Code Playgroud)
是的,它将是 UB:
一旦为一个对象调用了析构函数,该对象的生命周期就结束了;如果为生命周期已结束的对象调用析构函数,则行为未定义([basic.life] )。
[示例 2:如果显式调用具有自动存储持续时间的对象的析构函数,并且随后以通常会调用对象隐式析构的方式保留块,则行为未定义。— 结束示例]
p[50].~Handle();稍后delete[] p;将使其为生命周期已结束的对象调用析构函数。
因为p[50].value = 0;在对象的生命周期结束后,这适用:
在对象的生命周期开始之前但是在对象将占用的存储空间已经分配之后,或者在对象的生命周期结束之后并且在对象占用的存储空间被重用或释放之前,任何表示对象地址的指针可以使用物品将要或曾经所在的存储位置,但只能以有限的方式使用。对于正在构建或销毁的对象,请参阅
[class.cdtor]。否则,这样的指针指向分配的存储 ([basic.stc.dynamic.allocation]),并且使用该指针就好像该指针void*是明确定义的类型一样。允许通过这样的指针进行间接访问,但结果左值只能以有限的方式使用,如下所述。程序有未定义的行为,如果:6.2 -指针用于访问非静态数据成员或调用对象的非静态成员函数