-2

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));

14
  • 3
    What's wrong with an explicit default constructor using initialization list? Commented May 15, 2023 at 15:14
  • 4
    Just use this (default member initializers): int x{}; std::array<double,55> y{}; bool a{}; bool b{};. memset should not have to occur in current C++ at all. (std::fill). Or indeed just use initializer lists. Commented May 15, 2023 at 15:14
  • 5
    Your memset isn't safe at all. You should not make assumptions on how members are organized in memory (padding, alignment etc). Commented May 15, 2023 at 15:16
  • 2
    Side note: if you're going to cast pointers to integers, use intptr_t instead of regular old int. intptr_t is guaranteed to be large enough to hold an address. int is not. Commented May 15, 2023 at 15:19
  • 4
    @Caty Then do it "the right way": A() : x(), y(), a(), b() {}. T() has produced a value initialized (zero for fundamental types) since C++03 Commented May 15, 2023 at 15:24

1 Answer 1

4

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.

Sign up to request clarification or add additional context in comments.

12 Comments

Sure ? Try MSVC 2015 please and try to use () and see the result. And if I want to use an array of A a[55] how to zero initialize this ?
@Caty A a[55]{}; will do it if A is an aggregate.
@Caty -- I just tested with Visual C++ 2015, and there is no issues with the initialization. How are you verifying that the () does not work with VS 2015? Also, I used Service Pack 3, as that is the official version that actually implements C++11 as fully as possible. Before SP3, there were some language conformance issues (for example, static variables within functions not being thread-safe), so unless you are using something before SP3, I saw no issues.
@Caty Sorry, but I have no idea what you are talking about. Can you provide a concrete example in your question or via a godbolt link for which your compiler does not zero-initialize where you expect it or where sizeof(A) or memset(this, 0, sizeof(*this)); or A() : x(), y(), a(), b() doesn't work?
@Caty -- Again, how are you verifying your results? Are you using the debugger? Are you running a release version of your application? Did you write a simple program that actually std::cout's those values from the instance of A? If you are running a release version and using the debugger, please be aware that the compiler's optimizer does not have to initialize anything if it detects you are not accessing those member variables.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.