考虑这段代码:
auto buffer = new unsigned char[MAX_LEN];
auto hdr1 = new (buffer) Header1{ /* ... */ };
size_t pos1 = sizeof(Header1);
auto hdr2 = new (buffer + pos1) Header2{ /* ... */ };
size_t pos2 = pos1 + sizeof(Header2);
hdr2->data_len = fread(buffer + pos2, 1, MAX_LEN - pos2, stdin);
network_sendto(peer, buffer, pos2 + hdr2->data_len);
该代码的目的是将 Header1 的对象表示形式发送到网络,然后是 Header2 的对象表示形式,最后是用户数据。
当前标准是这么说的([basic.types.general]):
完整对象类型 T 的 对象表示 是由 T 类型的非位域完整对象占用的
Nunsigned char
对象序列,其中 N 等于。类型T的值表示是……类型T的非位域完整对象的对象和值表示分别是该对象对应的字节和位其类型的对象和值表示。 ......sizeof(T)
如果我理解正确的话,一旦缓冲区为 Header 提供存储,其中的一部分(“N
unsigned char
对象的序列”)会自动成为 Header 的对象表示。所以我认为代码是有效的。
这个答案末尾的代码示例似乎也同意。
我可以看到如何阅读该标准来暗示当
unsigned char
数组为对象提供存储时,那么与该对象占用相同存储空间的数组元素就是对象表示。然而,我不认为这就是它的真正含义。每个完整的对象都应该有一个符合 [basic.types.general]/4 的对象表示,包括那些没有放置在 unsigned char
缓冲区中的对象。这表明对象表示本质上是附属于一个完整对象的东西,而为其提供存储的数组是偶然的。该标准没有解释如何访问对象表示(P1839 旨在解决此问题),也没有指定在访问为对象提供存储的缓冲区元素时获得的值。 (如果我们从字面上理解标准,当将对象构造到缓冲区中或修改该对象时,数组的内容不会改变,因为没有规则会使数组元素的值改变,但是这显然是不对的。)
P1839 也没有说明提供存储的数组的内容。在 P1839 中,对象表示被明确声明为数组,但该数组是一个单独的对象,与提供存储的数组重叠(如果后者存在)。