It's clear that on the vast majority of platforms, an implementation which would process memcpy(anything, anything, 0) as a no-op, regardless of the validity of the source and destination pointers, would be in every way, in essentially every non-contrived scenario, as good or better than one that does anything else.
The way the Standard is written, however, could be interpreted as specifying that compilers are allowed to treat as UB any situation where the destination address is not associated with writable storage.
If one is using an implementation that seeks to process corner cases applying the philosophy documented in the Rationale document published by the authors of the Standard, without regard for whether the Standard unambiguously mandates such behavior, all memcpy
and memmove
operations where the size is zero will be reliably processed as no-ops. If the size will often be zero, there may be performance advantages to skipping a memcpy
or memmove
call in the zero-size case, but such a check would never be required for correctness.
If, however, one wishes to ensure reliable compatibility with compiler configurations that aggressively assumes that code will never receive inputs that trigger corner cases that aren't 100% unambiguously mandated by the Standard, and is designed to generate nonsensical code if such inputs are received, then it will be necessary to add a size==0 check in any case where a zero size might be accompanied by anything other than a pointer to writable storage, recognizing that such a check may negatively affect performance in situations where the size is very seldom zero.
const
memory, then it is an invalid pointer and the behaviour is undefined according to cppreference. – Statuesque0
bytes, then you are not writing to protected memory. You are not writing anything. – Lengthenconst
pointer. It's about passing a pointer that was originallyconst
when there is nothing to copy anyway. – Lengthenconst
variable, as the question makes quite clear.memset()
won't do anything. It won't dereference anything, or attempt to write anywhere. – Lengthenif
statement that checks the number of bytes to copy and calling memcpy only if it is not 0. I would expect modern C++ compilers to compile the whole thing away, making the whole thing a moot point without any worries of whether this is undefined behavior, or not. – Rigmemcpy
that make some things surprisingly undefined behavior. For examplememcpy( NULL, NULL, 0 )
is technically undefined behavior because the pointers passed in must be valid, even though no copy is actually occurring. As for my original question, I couldn't find anything in the standard covering this exact scenario, though there may be something in there. – Silkweedmemcpy
, so it's not unreasonable to see it in C++ code. – Ideomotorconst
memory or non-zero if it points to writable memory. So it's doubtful that the compiler will simply omit the call altogether, as it would in my trivial example. – Silkweedstd::bit_cast
take care of most or all of those situations? – MagnetizeZeroCountCheckedMemcpy
woud have defined behavior in that case butmemcpy
would not, omitting the check could adversely affect the behavior of what should be a Strictly Conforming C Program. – Levins