R Sahu R Sahu - 3 months ago 19
C++ Question

Why would the behavior of std::memcpy be undefined for objects that are not TriviallyCopyable?

From http://en.cppreference.com/w/cpp/string/byte/memcpy:


If the objects are not TriviallyCopyable (e.g. scalars, arrays, C-compatible structs), the behavior is undefined.


At my work, we have used
std::memcpy
for a long time to bitwise swap objects that are not TriviallyCopyable using:

void swapMemory(Entity* ePtr1, Entity* ePtr2)
{
static const int size = sizeof(Entity);
char swapBuffer[size];

memcpy(swapBuffer, ePtr1, size);
memcpy(ePtr1, ePtr2, size);
memcpy(ePtr2, swapBuffer, size);
}


and never had any issues.

I understand that it is trivial to abuse
std::memcpy
with non-TriviallyCopyable objects and cause undefined behavior downstream. However, my question:

Why would the behavior of
std::memcpy
itself be undefined when used with non-TriviallyCopyable objects? Why does the standard deem it necessary to specify that?

UPDATE

The contents of http://en.cppreference.com/w/cpp/string/byte/memcpy have been modified in response to this post and the answers to the post. The current description says:


If the objects are not TriviallyCopyable (e.g. scalars, arrays, C-compatible structs), the behavior is undefined unless the program does not depend on the effects of the destructor of the target object (which is not run by
memcpy
) and the lifetime of the target object (which is ended, but not started by
memcpy
) is started by some other means, such as placement-new.


PS

Comment by @Cubbi:


@RSahu if something guarantees UB downstream, it renders the entire program undefined. But I agree that it appears to be possible to skirt around UB in this case and modified cppreference accordingly.

Answer

It turns out that the standard does not say anything about the behavior of std::memcpy for objects that are not TriviallyCopyable. The contents of http://en.cppreference.com/w/cpp/string/byte/memcpy have been modified in response to the original post and the answers to the post. The current description says:

If the objects are not TriviallyCopyable (e.g. scalars, arrays, C-compatible structs), the behavior is undefined unless the program does not depend on the effects of the destructor of the target object (which is not run by memcpy) and the lifetime of the target object (which is ended, but not started by memcpy) is started by some other means, such as placement-new.

Comments