C++11 §3.8.1 声明,对于具有简单析构函数的对象,我可以通过分配给它的存储来结束它的生命周期。我想知道微不足道的析构函数是否可以通过“破坏对象”来延长对象的寿命并导致混叠问题,而我更早地结束了其寿命。
首先,我知道一些安全且无别名的东西
void* mem = malloc(sizeof(int));
int* asInt = (int*)mem;
*asInt = 1; // the object '1' is now alive, trivial constructor + assignment
short* asShort = (short*)mem;
*asShort = 2; // the object '1' ends its life, because I reassigned to its storage
// the object '2' is now alive, trivial constructor + assignment
free(mem); // the object '2' ends its life because its storage was released
现在,对于不太清楚的事情:
{
int asInt = 3; // the object '3' is now alive, trivial constructor + assignment
short* asShort = (short*)&asInt; // just creating a pointer
*asShort = 4; // the object '3' ends its life, because I reassigned to its storage
// the object '4' is now alive, trivial constructor + assignment
// implicitly, asInt->~int() gets called here, as a trivial destructor
} // 'the object '4' ends its life, because its storage was released
§6.7.2 声明自动存储持续时间的对象在作用域结束时被销毁,表明析构函数被调用。 如果有要销毁的 int,*asShort = 2
则违反别名,因为我正在取消引用不相关类型的指针。但是,如果整数的生命周期在 之前结束*asShort = 2
,那么我将在 short 上调用 int 析构函数。
我看到几个与此相关的竞争部分:
§3.8.8 读取
如果程序以静态 (3.7.1)、线程 (3.7.2) 或自动 (3.7.3) 存储持续时间结束 T 类型对象的生命周期,并且如果 T 具有非平凡的析构函数 39,则程序必须确保在隐式析构函数调用发生时原始类型的对象占据相同的存储位置;否则程序的行为是不确定的。
在我看来,他们用非平凡析构函数调用类型 T 作为产生未定义行为的事实似乎表明在该存储位置中定义了具有平凡析构函数的不同类型,但我在规范中找不到任何地方那定义了。
如果将平凡的析构函数定义为 noop,这样的定义将很容易,但规范中关于它们的内容非常少。
§6.7.3 表明允许 goto 跳入和跳出其变量具有普通构造函数和普通析构函数的范围。这似乎暗示了一种允许跳过琐碎的析构函数的模式,但是规范中关于在作用域末尾销毁对象的前面部分没有提到这一点。
最后,有一个时髦的阅读:
§3.8.1 表明我可以在我想要的任何时候开始一个对象的生命周期,如果它的构造函数是微不足道的。这似乎表明我可以做类似的事情
{
int asInt = 3;
short* asShort = (short*)&asInt;
*asShort = 4; // the object '4' is now alive, trivial constructor + assignment
// I declare that an object in the storage of &asInt of type int is
// created with an undefined value. Doing so reuses the space of
// the object '4', ending its life.
// implicitly, asInt->~int() gets called here, as a trivial destructor
}
这些阅读中唯一似乎暗示任何别名问题的阅读是§6.7.2 本身。看起来,当作为整个规范的一部分阅读时,微不足道的析构函数不应该以任何方式影响程序(尽管出于各种原因)。有谁知道在这种情况下会发生什么?