【发布时间】:2013-09-11 02:48:50
【问题描述】:
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 本身。看起来,当作为整个规范的一部分阅读时,微不足道的析构函数不应该以任何方式影响程序(尽管出于各种原因)。有谁知道在这种情况下会发生什么?
【问题讨论】:
-
这个问题是作为别名相关讨论的一部分出现的:stackoverflow.com/questions/18624449/…
-
很抱歉,这个问题和别名有什么关系?
-
@KerrekSB:显然是
asInt和asShort的别名。 -
根据编译器对琐碎析构函数所做的事情,我可能会同时将同一位置引用为 short 和 int,而不是 int,然后是短。
-
@BenVoigt:我看不到连接。别名是通过不匹配类型的左值“访问对象的存储值”。这不是在这里发生的。一个对象的生命周期结束,另一个对象的生命周期开始。我同意这是标准中令人尴尬的部分,但我希望看到对标准中感知到的问题或矛盾的更清晰的描述。
标签: c++ memory c++11 destructor