7

Consider the following code:

struct T {
    int a;
    union {
        struct {
            int a;
        } s1;
        struct {
            char b[1024];
        } s2;
    };
};

int main() {
    T x = T();
}

Since an explicit constructor is called, the above code ends-up zero-initializing all the data members in x.

But I would like to have x zero-initialized even if an explicit is not called. To do that one idea would be to initialize the data members in their declaration, which seems to be okay for T::a. But how can I zero-initialize all the memory occupied by the union by using the same criteria?

struct T {
    int a = 0;
    union {
        struct {
            int a;
        } s1;
        struct {
            char b[1024];
        } s2;
    };
};

int main() {
    T x; // I want x to be zero-initialized
}
Martin
  • 9,089
  • 11
  • 52
  • 87
  • http://stackoverflow.com/questions/1069621/are-members-of-a-c-struct-initialized-to-0-by-default – Joe Aug 04 '12 at 22:51

3 Answers3

10

You could zeroize using memset:

memset(&x, 0, sizeof(x));
MRAB
  • 20,356
  • 6
  • 40
  • 33
  • 4
    It's not unreasonable to use memset in C++. I think there's an iterator in that can be used with std::fill somehow to get the same effect, but memset is simpler. – celticminstrel Mar 11 '14 at 21:48
8

For a union without a user-defined default constructor, value initialization is zero initialization.

However, zero-initialization of a union may not zero all memory, but only the padding and the first member. If the first member isn't the largest, you could be left with non-zero content.

Since you know that s2 is largest, you can make a default constructor that zeros it:

struct T
{
    int a;
    union {
        int s1a;
        char s2b[1024];
    };
    T() : a(), s2b() {}
};

And now

T x;

will be zeroed.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • @Martin: No, it's not. But it is "standard layout". – Ben Voigt Aug 04 '12 at 23:10
  • Doesn't just adding '{}' to struct { char b[1024];} s2 = {}; solve my problem with union? In this case int main() { T x; } calls all the default-initializers, when the union is met, the following from the standard apply: "— if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor)" (see 8.5.1) – Martin Aug 04 '12 at 23:58
  • @Martin: Yes. Do note this sentence in section 9.5p2 "At most one non-static data member of a union may have a *brace-or-equal-initializer*." – Ben Voigt Aug 05 '12 at 00:02
  • 1
    Perhaps the Standard intents that the entire union object is filled with zero. The Standard says "the object's first non-static named data member is zero initialized and padding is initialized to zero bits;". With respect to an union's active object, the memory that follows it until the end of the union *is* actually padding I believe - reserved for when the union represents an object of its other member types. Note that there may not be any padding before the active object in an union. – Johannes Schaub - litb Aug 05 '12 at 09:46
  • @litb: You need some sort of reference to back up that interpretation of "padding bits", since "bits that are not part of the storage for *any* member" is also a viable definition, and it isn't by any means impossible for a union to contain bits that don't overlap any member, for alignment reasons. – Ben Voigt Aug 05 '12 at 13:17
3

I would suggest to implement a constructor for T:

struct T {
    int a;
    union {
        struct {
            int a;
        } s1;
        struct {
            char b[1024];
        } s2;
    };
    T() : a(), s2() {} // <- proper initialisation
};

In this case, I picked the largest member of your union since it's transparent. Otherwise you could explicitly create the union itself.

bitmask
  • 32,434
  • 14
  • 99
  • 159