views:

3011

answers:

5

I have a structure which I create a custom constructor to initialize the members to 0's. I've seen in older compilers that when in release mode, without doing a memset to 0, the values are not initialized.

I now want to use this structure in a union, but get errors because it has a non-trivial constructor.

So, question 1. Does the default compiler implemented constructor guarantee that all members of a structure will be null initialized? The non-trivial constructor just does a memset of all the members to '0' to ensure a clean structure.

Question 2: If a constructor must be specified on the base structure, how can a union be implemented to contain that element and ensure a 0 initialized base element?

A: 

Can you do something like this?

class Outer
{
public:
    Outer()
    {
     memset(&inner_, 0, sizeof(inner_));
    }
private:
    union Inner
    {
     int qty_;
     double price_;
    } inner_;
};

...or maybe something like this?

union MyUnion
{
    int qty_;
    double price_;
};

void someFunction()
{
    MyUnion u = {0};
}
John Dibling
We had considered that, but the structure we attempted to put in the union is in use in other parts of the code, so removing the constructor(assuming the compiler treats the struct as POD and doesn't intialize all elements to 0) could break code which depends on that.
Dan Pieczynski
+2  A: 

AFAIK union members may not have constructors or destructors.

Question 1: no, there's no such guarantee. Any POD-member not in the constructor's initialization list gets default-initialized, but that's with a constructor you define, and has an initializer list. If you don't define a constructor, or you define a constructor without an initializer list and empty body, POD-members will not be initialized.

Non-POD members will always be constructed via their default constructor, which if synthesized, again would not initialize POD-members. Given that union members may not have constructors, you'd pretty much be guaranteed that POD-members of structs in a union will not be initialized.

Question 2: you can always initialize structures/unions like so:

struct foo
{
    int a;
    int b;
};

union bar
{
    int a;
    foo f;
};

bar b = { 0 };
You can give the union itself a constructor that memset's itself to zero.
Greg Rogers
Good point! I keep forgetting about union constructors myself!
There is no difference between a programmers default constructor with no initializer list and empty body and a compiler generated constructor.
David Rodríguez - dribeas
@dribeas: thank you, I didn't write that very clearly, and updated my answer accordingly.
One difference is that the former renders the class non-POD, whereas the latter doesn't.
Steve Jessop
A: 

You'll have to wait for C++0x to be supported by compilers to get this. Until then, sorry.

Michel
+6  A: 

Question 1: Default constructors do initialize POD members to 0 according to the C++ standard. See the quoted text below.

Question 2: If a constructor must be specified in a base class, then that class cannot be part of a union.

Finally, you can provide a constructor for your union:

union U 
{
   A a;
   B b;

   U() { memset( this, 0, sizeof( U ) ); }
};

For Q1:

From C++03, 12.1 Constructors, pg 190

The implicitly-defined default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with an empty mem-initializer-list (12.6.2) and an empty function body.

From C++03, 8.5 Initializers, pg 145

To default-initialize an object of type T means:

  • if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
  • if T is an array type, each element is default-initialized;
  • otherwise, the object is zero-initialized.

To zero-initialize an object of type T means:

  • if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
  • if T is a non-union class type, each non static data member and each base-class subobject is zero-initialized;
  • if T is a union type, the object’s first named data member is zero-initialized;
  • if T is an array type, each element is zero-initialized;
  • if T is a reference type, no initialization is performed.

For Q2:

From C++03, 12.1 Constructors, pg 190

A constructor is trivial if it is an implicitly-declared default constructor and if:

  • its class has no virtual functions (10.3) and no virtual base classes (10.1), and
  • all the direct base classes of its class have trivial constructors, and
  • for all the nonstatic data members of its class that are of class type (or array thereof), each such class has a trivial constructor

From C++03, 9.5 Unions, pg 162

A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes. A union shall not be used as a base class.An object of a class with a non-trivial constructor (12.1), a non-trivial copy constructor (12.8), a non-trivial destructor (12.4), or a non-trivial copy assignment operator (13.5.3, 12.8) cannot be a member of a union, nor can an array of such objects

David Rodríguez - dribeas
What's missing here is that despite the name, default constructors do not default-initialize POD members. 12.6.2/4 says what happens when a member is not mentioned in an initializer list, and by your quote from 12.1, this applies to implicit ctors. It says, "If the entity is a non-static data member of ... class type ... and the entity class is a non-POD class, the entity is default-initialized ... otherwise, the entity is not initialized". So, POD data members are not initialized by the implicitly-generated constructor. Non-POD data members are default-initialized.
Steve Jessop
A: 

As mentioned in Greg Rogers' comment to unwesen's post, you can give your union a constructor (and destructor if you wish):

struct foo
{
    int a;
    int b;
};

union bar
{
    bar() { memset(this, 0, sizeof(*this)); }

    int a;
    foo f;
};
Adam Rosenfield
Looks like I need some education. Wouldn't memsetting the object to zero,wipe out the classes virtual table?
EvilTeach
@EvilTeach,Two things, 1) you don't have to use a vtable to implement polymorphism (except everybody does).2) Do you see any virtual methods on foo? Or any methods at all for that matter?. Does it inherit from anything? There's no vtable without virtual methods. In fact, were foo to have virtual methods and by extension a vtable it would no longer be a POD, and therefore ineligible for membership in the union.
Logan Capaldo