我试图完全理解 C++20 的一个新特性,即对象的隐式创建。
提案中的“3.3 类型双关语”部分中有此示例:
我们不希望以下示例有效:
Run Code Online (Sandbox Code Playgroud)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 行有效(在每种情况下),并允许浮动对象同样出现以使第 2 行有效。
为什么标有#X(由我)的行是必要的?这有什么不同吗?如果没有这条线,这个例子会不会完全一样?
我的推理是:buffer是一个字符数组,所以它隐式地创建了对象。因此,在第 1 行,int隐式创建了an 。同样,在第 2 行float,即使没有行 #X(因为buffer已经具有隐式创建对象属性),也会隐式创建a 。所以看起来#X 行没有添加任何内容。我错了吗?
为什么标有#X(由我)的行是必要的?
因为这会调用隐式对象创建。
C++20 中的隐式对象创建 (IOC) 并不混乱。它不是“每个对象每次都存在于每个可能的内存位置”。它是一种量子状态:当在一块内存上调用 IOC 规则时,会创建一个对象。你只是不知道它是什么。当您实际将内存用于特定对象时,结果证明这是在内存上调用 IOC 时创建的对象(或与之兼容的对象)。
如果你对存储做了任何事情,以至于单个对象不能同时满足两者,那么你就会得到 UB。
一段记忆不能在他们的一生中同时保存一个int和一个float。国际奥委会不会改变这一点。
第 1 行使用 IOCint在存储中创建一个;在这一点上,它在功能上与int buffer;. 第 2 行尝试访问float该存储中的 a,但不存在此类对象。如果int已经有一个,国际奥委会就不能float在它上面创建一个。
X 行通过重用存储来结束该内存中所有对象的生命周期;没有了int。并且由于创建的对象是byte数组,这也为IOC的存储重新加了福。这就是第 2 行工作的原因。