C++20中对象的隐式创建,理解提案的类型双关示例

Implicit creation of objects in C++20, understanding the type punning example of the proposal

我正在尝试完全理解 C++20 的一项新功能,对象的隐式创建。

proposal“3.3 类型双关”部分中有此示例:

We do not wish examples such as the following to become valid:

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
}

The proposed rule would permit an int object to spring into existence to make line #1 valid (in each case), and would permit a float object to likewise spring into existence to make line #2 valid.

为什么标记#X(由我)的行是必需的?这有什么不同吗?如果没有这一行,示例会不会完全相同?

我的推理是:buffer是一个字符数组,所以它隐式地创建了对象。因此,在第 1 行,隐式创建了一个 int。同样,在第 2 行,即使没有第 #X 行,也会隐式创建 float(因为 buffer 已经有隐式创建对象 属性)。所以#X 行似乎没有添加任何内容。我错了吗?

Why is the line marked #X (by me) necessary?

因为这会调用隐式对象创建。

C++20 中的隐式对象创建 (IOC) 不是混乱。它不是 "every object exists in every possible memory location at every time." 而是一种量子状态:当在一块内存上调用 IOC 规则时,会创建一个对象。你只是不知道它是什么。当您实际为特定对象使用内存时,结果发现这是在内存上调用 IOC 时创建的对象(或与之兼容的对象)。

如果您对存储进行任何操作,导致单个对象无法同时满足两者,那么您将获得 UB。

一块内存在其生命周期内不能同时容纳一个int和一个float。国际奥委会不会改变这一点。

第 1 行使用 IOC 在存储中创建一个 int;在这一点上,它在功能上与 int buffer; 没有什么不同。第 2 行尝试访问该存储中的 float,但不存在这样的对象。如果已经有 int,IOC 无法在其上创建 float

第 X 行通过重用存储结束了该内存中所有对象的生命周期;那里不再有 int。而且由于创建的对象是byte数组,这也为IOC重新加持了存储。这就是 Line 2 工作的原因。