Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing a union with a non-trivial constructor

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?

like image 868
Superpolock Avatar asked Nov 26 '08 16:11

Superpolock


People also ask

Can a union have a constructor?

A union can have member functions (including constructors and destructors), but not virtual functions. A union cannot have base classes and cannot be used as a base class. A union cannot have non-static data members of reference types.

What is a non trivial constructor?

If you define a constructor yourself, it is considered non-trivial, even if it doesn't do anything, so a trivial constructor must be implicitly defined by the compiler.

How do you initialize a union?

An initializer for a structure is a brace-enclosed comma-separated list of values, and for a union, a brace-enclosed single value. The initializer is preceded by an equal sign ( = ).

Can we initialize data members in a class without constructor?

Yes. This code: class MyClass { public: int a = 1; int b = 2; };


2 Answers

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

like image 171
David Rodríguez - dribeas Avatar answered Oct 02 '22 19:10

David Rodríguez - dribeas


Things changed for the better in C++11.

You can now legally do this, as described by Stroustrup himself (I reached that link from the Wikipedia article on C++11).

The example on Wikipedia is as follows:

#include <new> // Required for placement 'new'.  struct Point {     Point() {}     Point(int x, int y): x_(x), y_(y) {}     int x_, y_; };  union U {     int z;     double w;     Point p; // Illegal in C++03; legal in C++11.     U() {new(&p) Point();} // Due to the Point member, a constructor                            // definition is now *required*. }; 

Stroustrup goes into a little more detail.

like image 21
dan-man Avatar answered Oct 02 '22 19:10

dan-man