On 2/14/23 06:57, Chris Vine wrote:
> On Tuesday, 14 February 2023 at 07:54:41 UTC, James Kuyper wrote:
...
>> "For any object (other than a potentially-overlapping subobject) of
>> trivially copyable type T, whether or not the object holds a valid
>> value of type T, the underlying bytes (6.7.1) making up the object
>> can be copied into an array of char, unsigned char, or std::byte
>> (17.2.1).36" 6.8p2.
>> The "36" at the end of that citation references footnote 36, which says:
>> "By using, for example, the library functions (16.5.1.2) std::memcpy
>> or std::memmove."
...
> It is true that [intro.object]/8 provides that "an object of trivially
> copyable or standard-layout type (6.8) shall occupy contiguous bytes
> of storage", and [basic.types]/2 provides that in the case of a
> trivially copyable type such contiguous bytes may be copied by
> memcpy(), but I don't agree that the fact that the C++ standard
> imports memcpy() from C in order to do so means that pointer
> arithmetic necessary to implement a user-side version of the function
> is automatically validated. You could view memcpy() as a built-in
> black box which the compiler must in some way known only to itself
> provide in order to comply with [basic.types]/2.
If that were the case, the normative text would mandate the use of
std::memcpy() or std::memmove(). It doesn't. It merely specifies "the
underlying bytes (6.7.1) making up the object can be copied into an
array of char, unsigned char, or std::byte", without specifying the
methods that can be used to achieve that result. memcpy and memmove are
mentioned only non-normatively as ways that you could cause such a copy
to occur, without specifying that they are the only ways.
> But we don't need to argue about that because I think that you can
> implement memcpy() in C++ by relying on the fact that any single
> object (including any individual byte) can be treated as an array of
> one element for pointer arithmetic purposes ([basic.compound]/3), so
> you can validly increment a pointer to any one byte to one past the
> byte, which in the case of the contiguous bytes of a trivially
> copyable type will also be a pointer to the next byte, and progress in
> that way.
I don't agree that this is necessary in order for the code to have
well-defined behavior. However, since memcpy() and memmove() can be
implemented using exclusively increment or decrement operations, and the
same can be done in user code, I don't see this as an argument
preventing user code from copying the object byte-by-byte.