Zero initialization using the best and easy solution

294 Views Asked by At

Because of differences for zero initialization between compilers when using () {} I prefer memset. How safe is this code ?

class A {
public:
  int x;
  double y[55];
  bool a, b;
  A() {
    memset(&x, 0, int(&b)+sizeof(bool)-int(&x));// cannot use sizeof(A) but I know address of first and last
  }
};

I do not have user-defined types, classes, structs from x variable to b variable. I know the address of the first variable and the last. Can I be sure that all the variables defined between x and b, including those in array are zero in all MSVC and Mac compilers after 2010 ?

_____ EDITED _____

Who consider this duplicate, please show me where in the "original" is this solution: memset(&x, 0, int(&b)+sizeof(bool)-int(&x)); ???

This is the key for using memset(), not professional at all to close the thread like this !!!

In meantime I find a more good solution: memset(&x, 0, size_t(&b)+sizeof(bool)-size_t(&x));

1

There are 1 best solutions below

12
On

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 memseting 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.