关于下面的代码
int main()
{
struct S { int i; } s { 42 };
new (&s.i) int { 43 };
}
动态存储持续时间与new表达式创建的对象相关联。
There is similar question,同意新放置的位置创建具有动态存储持续时间的对象。因为没有其他措辞可以适用于该问题中的示例。
这是一个精心设计的示例,其中有措辞说出一些有趣的东西。 [basic.stc.inherit]/1说:
子对象和引用成员的存储期限是其完整对象的期限
和[intro.object]/2保证创建的int
对象是s
的子对象:
如果在与成员子对象或数组元素e(可能在其生命周期内或可能不在其生命周期内)关联的存储器中创建对象,则在以下情况下,创建的对象是e的包含对象的子对象:
(要求已得到满足,我不会在此处复制它们)
那么,新创建的int
对象具有哪个存储期限?是动态还是自动?
答案 0 :(得分:1)
这个问题很有趣。的确,有关动态存储持续时间和new
表达式的措辞并不排除新的放置位置。
表述含糊不清是由于需要处理的各种情况引起的:
int main()
{
struct Simple { int i; } s { 42 };
new (&s.i) int { 43 }; // the lifecyle of the newly created object
// will auto, since Simple will be destroyed when
// going out of scope
struct Complex { char s[256]; } c;
Simple *p = new (&c.s) Simple; // the lifecycle of the newly created object
// is dynamic. You'll need to delete it in time.
// because compiler doesn't know about its true nature
// and memory will be lost when going out of scope
}
幸运的是,该标准足够精确,因此,如果您提供正确的代码(即没有UB),则每个编译器都会产生相同的结果。
实际上,动态创建对象(放置新对象)并不一定意味着对象生命周期与创建对象的范围无关。但是,您需要确保在适当的时候销毁对象,因此将其视为动态存储持续时间。
这里的关键是分配。只有内存分配才能使对象持续时间真正独立于创建对象的范围。这是在标准中表达的,但可能不尽如人意。让我们从 basic.stc/2 中的完整子句开始:
静态,线程和自动存储持续时间与 对象由声明引入,由对象隐式创建 实施。动态存储持续时间与 由new表达式创建的对象。
我会在这里理解,只有当对象没有被第一句覆盖时,最后一句才适用。但这是目前的个人解释。因此,唯一可以确定的是,如果出现重叠,则需要格外小心。
因此,让我们仔细看看动态存储持续时间[basic.stc.dynamic] / 1
可以在程序执行期间动态创建对象(...)。 C ++实现提供对以下内容的访问和管理: 通过全局分配功能运算符new和 运算符new []和全局释放函数运算符delete 和运算符delete []。 [注意: 21.6.2.3不执行分配或取消分配。 —尾注]
第二句话清楚地表明动态存储意味着分配。然后是有趣的注释,它恰好指的是 [new.delete.placement] / 1 一章:
这些功能是保留的; C ++程序可能未定义函数 用于替换C ++标准库中的版本。 6.7.4的规定不适用于以下保留的表格 运算符new和运算符delete。
6.7.4部分是 basic.stc.dynamic 部分。这意味着用于新放置的特殊分配不会创建动态存储。
动态存储和动态存储持续时间不是一个事实,并且同一件事使整个内容难以表达:
这里有一个 online demo ,用于新放置和销毁,并查看当封闭对象超出范围时会发生什么。它使用Tracer
类,将比int
突出显示不同的情况(包括在调用新的展示位置之前删除先前的对象)。
结论:我认为,在具有如此悠久的历史和如此众多的贡献者的任何标准中,都无法避免某些歧义和循环性。但是在这种情况下,您可以看到问题本身具有您最初期望的更多方面。