It is not very rare to find a library that zeros its objects in the constructors using memset. And sometimes it happens to empty classes as well. Is it safe, especially when one inherits such classes?
Consider the following example:
#include <iostream>
#include <cstring>
struct A { char a; };
struct B {
B() { std::memset( this, 0, sizeof(B) ); }
};
struct C : A, B {};
static_assert( sizeof(C) == 1 );
int main() {
std::cout << (int)C{ {1}, {} }.a
<< (int)C{ {1}, B{} }.a;
}
GCC prints here 00, Clang prints 01 and MSVC prints 11 while emitting
warning C4789: buffer '' of size 1 bytes will be overrun; 1 bytes will be written starting at offset 1
Online demo: https://gcc.godbolt.org/z/jW1edecrd
Is it defined behavior? And if yes, which compiler is correct here?
This is undefined.
The only objects for which you can copy bytes over them and the standard guarantees anything are objects of trivially copyable types which are not potentially overlapping subobjects (ref):
A potentially-overlapping subobject is (ref):
So, according to the standard, this is not safe for any class usable as a base class.
It's also worth adding that this does not require an empty class to have overlapping storage in practice either:
B::a is stored in the tail padding for A on Linux. godbolt