The assignment operator is not defined in terms of memcpy
(§12.8/28).
The implicitly-defined copy/move assignment operator for a non-union
class X performs memberwise copy/move assignment of its subobjects.
The direct base classes of X are assigned first, in the order of their
declaration in the base-specifier-list, and then the immediate
non-static data members of X are assigned, in the order in which they
were declared in the class definition. Let x be either the parameter
of the function or, for the move operator, an xvalue referring to the
parameter. Each subobject is assigned in the manner appropriate to its
type:
[...]
— if the subobject is an array, each element is assigned, in the
manner appropriate to the element type;
[...]
As you see, each char
element will be assigned individually. That is always safe.
However, under the as-if rule, a compiler may replace this with a memmove
because it has identical behaviour for a char
array. It could also replace it with a memcpy
if it can guarantee that memcpy
will result in this same behaviour, even if theoretically such a thing is undefined. Compilers can rely on theoretically undefined behaviour; one of the reasons undefined behaviour exists is so that compilers can define it to whatever is more appropriate for their operation.
Actually, in this case a compiler could take the as-if rule even further and not do anything with the array at all, since that also results in the same behaviour.