c++language-lawyerplacement-newtype-punning

Does "providing storage" mean being the "object representation"?


Consider this code:

auto buffer = new unsigned char[MAX_LEN];
//Ommiting assertions that the header structs are carefully designed to meet certain align and size requirements.
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);

The code is intended to send the object representation of Header1, followed by that of Header2, followed by the user data, to the network.

The current standard says this ([basic.types.general]):

The object representation of a complete object type T is the sequence of N unsigned char objects taken up by a non-bit-field complete object of type T, where N equals sizeof(T). The value representation of a type T is ...... The object and value representation of a non-bit-field complete object of type T are the bytes and bits, respectively, of the object corresponding to the object and value representation of its type. ......

If I understand it correctly, once the buffer provides storage for the Header, part of it ("the sequence of N unsigned char objects") automatically becomes the object representation of the Header. So I think the code is valid. And a code sample in the end of this answer also seems to agree.

  1. Is the above reasoning correct? Does the code exhibit UB in some aspects?
  2. I'd also like to know if it is still valid if P1839 goes into the standard. Because that paper seems to touch the definition of object representation.

Solution

  • I can see how the standard might be read to imply that when an array of unsigned char provides storage for an object, then the elements of the array that occupy the same storage as the object are the object representation. However, I don't think that's what it really means. Every complete object is supposed to have an object representation according to [basic.types.general]/4, including ones that aren't placed in an unsigned char buffer. This suggests that the object representation is something inherently attached to a complete object, and the array that provides storage for it is incidental. The standard doesn't explain how you can access the object representation (P1839 aims to fix this), nor does it specify what values you get if you access the elements of the buffer that's providing storage for the object. (If we read the standard very literally, the contents of the array don't change when an object is constructed into the buffer or when that object is modified, because there are no rules that would make the values of the array elements change, but this obviously can't be right.)

    P1839 also doesn't say anything about the content of the array that's providing storage. In P1839, the object representation is explicitly stated to be an array, but that array is a separate object that overlaps with the array that's providing storage (if the latter exists).