0

Initializing member variables in the constructor

As you might know, it is good practice to leave no variables uninitialized. If you wrote a struct or class, all its members should have a defined initial state, which is usually set in the struct’s or class’s constructor.

Basics

Let’s say we have a struct like this:

struct MyStruct
{
  LONG _i;
  Real _x;
  Vector _v;
};

To give all members a defined initial state, add a constructor:

struct MyStruct
{
  LONG _i;
  Real _x;
  Vector _v;

  MyStruct()
  {
    _i = 0;
    _x = RCO 0.0;
    _v = Vector(RCO 0.0);
  }
};

Now we have a defined initial state for each member variable. Crashes and surprises caused by uninitialized variables are now impossible.

But let’s take a close look at what happens… when an instance of the struct is constructed, the memory for each of the member variables is allocated. Then, in the constructor, the variables are filled with values that have also been constructed. So, all in all, we have double as much constructions as necessary.

A better idea is this:

struct MyStruct
{
  LONG _i;
  Real _x;
  Vector _v;

  MyStruct() : _i(0), _x(RCO 0.0), _v(RCO 0.0)
  {  }
};

This way, the member variables are constructed with their initial value, instead of being constructed and then filled with their initial values. The difference may seem small, but in a time-critical it pays off.

Note: It is important to initialize the member variables in the very same order in which they were declared!

More constructors

Of course, overloaded constructors offering the possibility to pass initial values or to copy them from another instance of the same struct are also possible:

struct MyStruct
{
  LONG _i;
  Real _x;
  Vector _v;

  // Default constructor
  MyStruct() : _i(0), _x(RCO 0.0), _v(RCO 0.0)
  {  }

  // Copy constructor
  MyStruct(const MyStruct& src) : _i(src._i), _x(src._x), _v(src._v)
  {  }

  // Constructor for passing initial values
  MyStruct(LONG i, Real x, const Vector& v) : _i(i), _x(x), _v(v)
  {  }
};

If members have to be allocated

If you have any member that needs to be allocated, e.g. an array, then you must either do that in the constructor body (done e.g. in the copy constructor), or initialize the pointer with NULL (done in the default constructor) and allocate it later at some point. Also, take care to free the memory, of course.

struct MyStruct
{
  LONG _i;
  Real _x;
  Vector _v;
  Real* _arr;

  // Default constructor
  MyStruct() : _i(0), _x(RCO 0.0), _v(RCO 0.0), _arr(NULL)
  {  }

  // Copy constructor (Array copied manually from the source!)
  MyStruct(const MyStruct& src) : _i(src._i), _x(src._x), _v(src._v)
  {
    if (_i > 0 && src._arr)
    {
      _arr = GeAllocTypeNC(Real, _i);
      if (_arr)
        CopyMemType(Real, src._arr, _arr, _i);
    }
  }

  // Constructor for passing initial values
  MyStruct(LONG i, Real x, const Vector& v) : _i(i), _x(x), _v(v)
  {
    if (_i > 0)
    {
      _arr = GeAllocType(Real, _i);
    }
  }

  // Destructor, to free the array
  ~MyStruct()
  {
    if (_arr)
      GeFree(_arr);
  }
};

One thing you might notice is that GeAllocTypeNC() is used in the copy constructor. Of course, GeAllocType() would also do the job, but GeAllocTypeNC() does not initialize the allocated memory with 0, so we save a bit of time. The array is filled with values right after that, anyway, using CopyMemType().

Frank Willeke

worked with computers since more than 20 years | got hooked on computer graphics back on the AMIGA | started programming at the age of 13 | relesed some successful plugins for cinema 4d | started working for maxon computer gmbh in 2009 | now contributing to cinema 4d as a senior developer

making electronic music since 1993 | playing the electric guitar since 1995 age of 14 | first live gigs in 1997 | playing the bass guitar 2005 | playing keyboards and synths since 2012

experimenting with photography since 2003

Leave a Reply

Your email address will not be published. Required fields are marked *