我试图完全理解C ++ 20的新功能,即对象的隐式创建。
proposal的“ 3.3 Type punning”部分中有此示例:
我们不希望以下示例有效:
float do_bad_things(int n) { alignof(int) alignof(float) char buffer[max(sizeof(int), sizeof(float))]; *(int*)buffer = n; // #1 new (buffer) std::byte[sizeof(buffer)]; // #X return (*float*)buffer; // #2 }
建议的规则将允许int对象出现以使第1行有效(在每种情况下,并且将允许float对象同样存在以使第2行有效。
为什么标记为#X(我自己)的行是必需的?这有什么不同吗?如果此行不存在,示例是否会完全相同?
我的推理是:buffer
是一个char数组,因此它隐式创建对象。因此,在第1行,隐式创建了int
。同样,在第2行,即使没有第#X行,也会隐式创建float
(因为buffer
已经具有隐式创建对象属性)。因此,似乎#X行没有添加任何内容。我错了吗?
为什么标记为#X(我自己)的行是必需的?
因为调用隐式对象创建。
C ++ 20中的隐式对象创建(IOC)不是chaos。并不是“每个时间每个对象都存在于每个可能的内存位置中”。相反,它是一种量子状态:当在一块内存上调用IOC规则时,将创建一个对象。您就是不知道那是什么。当您实际将内存用于特定对象时,事实证明这是在内存上调用IOC时创建的对象(或与其兼容的对象)。
并且如果您对存储执行任何操作以使单个对象不能同时满足这两个条件,那么您将得到UB。
一块内存不能同时保存其生命周期中的int
和float
。国际奥委会不会对此进行更改。
第1行使用IOC在存储中创建一个int
;在这一点上,它在功能上与int buffer;
没有区别。第2行尝试访问该存储中的float
,但不存在此类对象。如果已经有int
,则IOC无法在其顶部创建float
。
X行通过重新使用存储来结束该内存中所有对象的生存期;不再有int
。并且由于创建的对象是byte
数组,因此这也为IOC重新提供了存储空间。这就是使2号线正常工作的原因。