Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Class construction with initial values

Tags:

c++

I'm new to C++, and the whole idea of classes - I'm still reading a book to try and learn. The book I'm reading says that when I construct a class, I can assign default values by doing this:

class foo {
public:
   foo(char c, int i);
private:
   char exampleChar;
   int exampleInt;
};

foo::foo(char c, int i):
exampleChar(c),
exampleInt(i)
{}

This code (to me) looks very messy, and doesn't follow rules that I'm used to in other languages. My question is, what's the difference between doing the above, and this (below, which I personally think looks a lot cleaner)?

foo::foo(char c, int i) {
   exampleChar = c;
   exampleInt = i;
}

Sort of things I'm thinking about are: are there performance/efficiency issues if done on a large scale - or is it exactly the same?

like image 367
Jonathon Avatar asked Aug 26 '11 16:08

Jonathon


2 Answers

The first way, by doing : exampleChar(c), exampleInt(i) is called an initializer list.

If you do it the second way, the two variables are default constructed first1, then you assign them a value. (When the actual body of the constructor is entered, anything that hasn't been initialized by the initializer list is default constructed.) This is a waste of time because you're just overwriting the values anyway. For small types like int or char this isn't a big deal, but when those member variables are large types that would take lots of cycles to construct, you definitely want to use the initializer list.

The second way won't waste time giving them a default value and then overwriting it - it will set their values directly to that value you give it (or call the right constructor if the member is an object).

You can see what we mean by doing this:

class MyClass {
public:
    int _i; // our data

    // default constructor
    MyClass() : _i(0) { cout << "default constructor"; }

    // constructor that takes an int
    MyClass(int i) : _i(i) { cout << "int constructor"; }

    // assignment operator
    void operator=(int i) { _i = i; cout << "assignment operator"; }
};

class OtherClass {
public:
    MyClass c;

    OtherClass() {
        c = 54;
    }
};

OtherClass oc;

You'll see that

default constructor
assignment operator

is printed. That's two function calls which, for other classes, could be expensive.

If you change the constructor of OtherClass to

OtherClass() : c(54) {   }

You'll see that

int constructor

is printed. Just one call compared to two. This is the most efficient way.

Initializer lists are also a must when you

  1. have types that have no default constructor. You have to call the right constructor in the initializer list.

  2. have a const member that you want to give some value (rather than just have permantently the default value

  3. have a reference member. You must use initializer lists on these.

tl;dr: do it because it's at least as fast but never slower than the other way, and sometimes far faster.

1 For built in types like int and char, they are actually not constructed at all; they just have the value of whatever memory they happen to have had previously.

like image 178
Seth Carnegie Avatar answered Oct 19 '22 02:10

Seth Carnegie


The difference is that the compiler will always initialize all members (in declaration order) prior to the first user-defined constructor statement. In the case of a char and an int, which are both primitive types, 'initialization' actually means 'no initialization' here. However, if you have a member with a constructor that does some actual work, this constructor will be called upfront - if you do

foo::foo() {
    myComplexMember = MyComplexClass(42);
}

the compiler did already invoke the MyComplexClass default constructor before your code got called, which is a waste of resources (and a compiler error if the default ctor is not accessible).

By using an initialization list, you can customize the default initialization and avoid doing things for nothing. Obviously, this is the way to go.

like image 41
Alexander Gessler Avatar answered Oct 19 '22 03:10

Alexander Gessler