9
class Node
{
public:

    Node *parent; // used during the search to record the parent of successor nodes
    Node *child; // used after the search for the application to view the search in reverse

    float g; // cost of this node + it's predecessors
    float h; // heuristic estimate of distance to goal
    float f; // sum of cumulative cost of predecessors and self and heuristic

    Node() :
            parent( 0 ),
            child( 0 ),
            g( 0.0f ),
            h( 0.0f ),
            f( 0.0f )
    {
    }

    UserState m_UserState;
};

Why we should use the constructor

    Node() :
            parent( 0 ),
            child( 0 ),
            g( 0.0f ),
            h( 0.0f ),
            f( 0.0f )
    {
    }

instead of

    Node()
    {
        parent = null;
        child = null;
        g = 0.0f;
        h = 0.0f;
        f = 0.0f;
    }

Thanks :)

razlebe
  • 7,134
  • 6
  • 42
  • 57
Dzung Nguyen
  • 9,152
  • 14
  • 65
  • 104

5 Answers5

14

For plain old data (POD), this has little benefit, but once you start either using references or composing classes it makes a difference:

class Foo {
    Bar bar;

  public:
    // construct bar from x
    Foo(int x) : bar(x) { }
};

versus

Foo::Foo(int x)
{
    // bar is default-constructed; how do we "re-construct" it from x?
    bar = x;  // requires operator=(int) on bar; even if that's available,
              // time is wasted default-constructing bar
}

Sometimes, you won't even have a way of "re-constructing" an object once it has been constructed, as a class may not support setters or operator=. const members can certainly not be "re-constructed" or reset:

class FooWithConstBar {
    const Bar bar;

  public:
    Foo(int x) {
        // bar is cast in stone for the lifetime of this Foo object
    }
};

Edit: thanks to @Vitus for pointing out the problem with references.

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • Ahhh, you updated your post regarding constness while I wrote mine. I'm really getting sick of the "fastest gun in the west" syndrome. – rjnilsson Apr 19 '11 at 10:57
  • 3
    Also references cannot be assigned in constructor's body and must be initialized in initializer list. – Vitus Apr 19 '11 at 12:44
6

As there are some circumstances where you actually need or by performance reasons should initialize members using an initialization list, you should be consistent and always use it.

Examples where you need to use initialization lists is when an aggregate has no default constructor or when you have const members (yes, uncommon, but allowed).

An example where when you should (but aren't forced to) use initialization lists is when you have an aggregate object and the following points are valid:

  • The aggregate has a default constructor.
  • You need to setup the object with non-default values.
  • The aggregate has a constructor that allows you to set the desired non-default values.

Now then - why should you not use it?

rjnilsson
  • 2,343
  • 15
  • 20
  • 1
    I can think of wholly artificial cases where you want the order of initialization of two objects to be different depending on some flag to the constructor. `if (a) { b = new X(NULL); c = new Y(b); } else { c = new Y(NULL); b = new X(c); }`. It smells bad to me even in example form - but it cannot be done with initialization lists. –  Apr 19 '11 at 11:44
  • @Joe: Can you come up with an example that doesn't involve allocation of a resource? The behaviour is well defined if an exception is thrown during initialization in the member init list, but in the example you have here you will have to write quite a bit of code to guarantee that memory is freed correctly should the constructor for X, Y or the call to 'new' throw an exception. – Richard Corden Apr 19 '11 at 18:22
  • (+1) It might be worth while including information on the guarantees that are given should an exception be thrown during initialization in the member init list. – Richard Corden Apr 19 '11 at 18:25
  • @Richard: I can't think of one that doesn't require allocation of a resource, but to be flippant, `b` and `c` are already smart pointers in my example so memory is guaranteed to free correctly. ;) –  Apr 19 '11 at 18:34
  • @Joe: Aha, smart pointers with implicit one-argument constructors accepting a raw pointer ... rare :) One thing though: I actually think that it is _possible_ to implement your artificial case using initialization lists and helper methods that returns the init values, but it would be even uglier. – rjnilsson Apr 20 '11 at 06:39
3

Prefer initialization lists

dubnde
  • 4,359
  • 9
  • 43
  • 63
2

Mainly because of performance issues.

It's discussed here.

razlebe
  • 7,134
  • 6
  • 42
  • 57
M'vy
  • 5,696
  • 2
  • 30
  • 43
1

The main reason is object validity and class invariants. Another reason is ease of use.

If you put everything in the constructor then when the constructor finishes you are guaranteed a valid Node. If you had to set all the instance variables separately then it would be possible to have a Node with some of the variables uninitialised either because the programmer forgot or if one of the assignments throws an exception. The latter would not occur in your case but in general it could. If the Node is not fully initialised its behaviour cannot be guaranteed to be as you expect.

mmmmmm
  • 32,227
  • 27
  • 88
  • 117