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

gez*_*eza 3 c++ c++20

我试图完全理解 C++20 的一个新特性,即对象的隐式创建。

提案中的“3.3 类型双关语”部分中有此示例:

我们不希望以下示例有效:

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
}
Run Code Online (Sandbox Code Playgroud)

提议的规则将允许 int 对象出现以使第 1 行有效(在每种情况下),并允许浮动对象同样出现以使第 2 行有效。

为什么标有#X(由我)的行是必要的?这有什么不同吗?如果没有这条线,这个例子会不会完全一样?

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

Nic*_*las 6

为什么标有#X(由我)的行是必要的?

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

C++20 中的隐式对象创建 (IOC) 并不混乱。它不是“每个对象每次都存在于每个可能的内存位置”。它是一种量子状态:当在一块内存上调用 IOC 规则时,会创建一个对象。你只是不知道它是什么。当您实际将内存用于特定对象时,结果证明这是在内存上调用 IOC 时创建的对象(或与之兼容的对象)。

如果你对存储做了任何事情,以至于单个对象不能同时满足两者,那么你就会得到 UB。

一段记忆不能在他们的一生中同时保存一个int和一个float。国际奥委会不会改变这一点。

第 1 行使用 IOCint在存储中创建一个;在这一点上,它在功能上与int buffer;. 第 2 行尝试访问float该存储中的 a,但不存在此类对象。如果int已经有一个,国际奥委会就不能float在它上面创建一个。

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