Because of differences for zero initialization between compilers when using () {}
There is no difference. It is standardized and hasn't been changed significantly since C++03 in the case of ()
and since C++11 with the addition of {}
. In particular both ()
and {}
would have the same effect if your class didn't have a constructor and both would zero-initialize. If your class does have a user-declared/provided constructor, then the class isn't aggregate and so neither ()
nor {}
will cause zero-initialization.
The memset on the other hand has implementation-defined behavior at best. In particular int(&b)
is only allowed if int
is large enough to hold a pointer value (i.e. it will fail on common 64bit systems). If it does work it has an implementation-defined value and everything you do with it is also implementation-defined.
Whether memset
on a pointer to x
instead of the A
object is allowed at all, is another issue of concern.
If A
wasn't trivially-copyable, then memset
would have undefined behavior regardless.
The correct way to zero-initialize all members of a class explicitly with a non-aggregate class, i.e. one that has a user-declared/provided constructor, is to use the member initializer list to individually value-initialize the members, since C++03 like this:
A() : x(), y(), a(), b() { /* do constructor things */ }
(With C++11 or later {}
default member initializers may be used instead as well.)
This initializes everything to zero, except padding. If you really need that for some reason and your class is trivially-copyable and *this
isn't potentially overlapping (i.e. it isn't used as a base class subobject or a member subobject with [[no_unique_address]]
), then a correct memset
use would be:
memset(this, 0, sizeof(*this));
However, note that memset
ing all bytes to zero technically also doesn't imply that the members will be set to value zero. It is valid for an implementation to use a different bit pattern than all-zero to represent the zero or null pointer value of a scalar type.