Constructor initialization lists

J

Jef Driesen

Hello,

Suppose I have a class that looks like this:

class point {
protected:
unsigned int m_x, m_y; // OR unsigned int m_data[2];
public:
point();
point(unsigned int x, unsigned int y);
point(const point& p);
point& operator= (const point& p);
};

I know it is preferable to use initialization lists to initialize member
variables in a constructor:

point::point(unsigned int x, unsigned int y)
: m_x(x), m_y(y) {}
{
}

over assignments within the constructor body:

point::point(unsigned int x, unsigned int y)
{
m_x = x;
m_y = y;
}

In the second example, the default constructor for each data member is
invoked prior to the assignment in the constructor body. This will
result in lower performance (overhead of calling the unnecessary default
constructor).

But what if I replace the data members with an array? Now I can only use
assignment in the constructor body:

point::point(unsigned int x, unsigned int y)
{
m_data[0] = x;
m_data[1] = y;
}

My questions are:
(1) How is m_data initialized *before* the assignment in the body?
(2) Will this result in lower performance?
 
K

Karl Heinz Buchegger

Jef said:
[snip]

But what if I replace the data members with an array? Now I can only use
assignment in the constructor body:

Right.
That's because arrays are what we call 'half baked types'. Arrays behave
differently in many aspects then other types.
point::point(unsigned int x, unsigned int y)
{
m_data[0] = x;
m_data[1] = y;
}

My questions are:
(1) How is m_data initialized *before* the assignment in the body?

In this specific case: Not at all. int, unsigned int, char, float, double,
pointers (the 'builtin types') are *not* default initialized at all. They
simply contain what was in memory before the variable was placed there.
Usually its just garbage.

If you have an array of some class type however (eg. std::string), the default
constructor will be called for each array member.
(2) Will this result in lower performance?

Depends: If you have an array of builtin type, then no. Usually this won't
result in lower performance. If however the default constructor is run for
each array member, then yes, most likely this will result in lower performance.
It depends on what the default constructor has to do.
 
B

Bob Hairgrove

Hello,

Suppose I have a class that looks like this:

class point {
protected:
unsigned int m_x, m_y; // OR unsigned int m_data[2];
public:
point();
point(unsigned int x, unsigned int y);
point(const point& p);
point& operator= (const point& p);
};

I know it is preferable to use initialization lists to initialize member
variables in a constructor:

point::point(unsigned int x, unsigned int y)
: m_x(x), m_y(y) {}
{
}

over assignments within the constructor body:

point::point(unsigned int x, unsigned int y)
{
m_x = x;
m_y = y;
}

In the second example, the default constructor for each data member is
invoked prior to the assignment in the constructor body...

POD-types are NOT default constructed or initialized, their value is
undefined. In order to default initialize an unsigned int, you must
write:

point::point(unsigned int x, unsigned int y)
: m_x(), m_y()
{
m_x = x;
m_y = y;
}
... This will result in lower performance (overhead of calling
the unnecessary default constructor).

For unsigned int, there is no performance loss to speak of. For
non-POD types, there might be ... depends on how the default
constructor (if any) and operator= (if overloaded) is implemented.
Also, it depends on how the compiler might optimize things. You have
to test to make sure.
But what if I replace the data members with an array? Now I can only use
assignment in the constructor body:

point::point(unsigned int x, unsigned int y)
{
m_data[0] = x;
m_data[1] = y;
}

My questions are:
(1) How is m_data initialized *before* the assignment in the body?

It isn't. The compiler only reserves storage for an array of two
unsigned ints. Its contents are initially garbage. Of course, if the
members are of non-POD type, they must be default constructible, in
which case the default constructor is called once for each element.
But unsigned int is POD.
(2) Will this result in lower performance?

See my remarks above. You won't know until you have tested it.

(I believe it was Donald Knuth who said: "Premature optimization is
the root of all evil.")
 
J

Jacek Dziedzic

Bob said:
It isn't. The compiler only reserves storage for an array of two
unsigned ints. Its contents are initially garbage. Of course, if the
members are of non-POD type, they must be default constructible, in
which case the default constructor is called once for each element.
But unsigned int is POD.

I think the OP meant "how can I initialize m_data *before*..."
rather than "how is it that m_data gets initialized".

to the OP:
There is no way to initialize arrays inside the constructor
init-list. The same goes for members of structs.

Don't worry about it if these are variables of built-in types.
Only if their default-construction is time-costly, you should
care.

HTH,
- J.
 
R

Ron Natalie

Karl said:
In this specific case: Not at all. int, unsigned int, char, float, double,
pointers (the 'builtin types') are *not* default initialized at all. They
simply contain what was in memory before the variable was placed there.
Usually its just garbage.

Actually, they might or might not be default initialized. It depends how
the storage is allocated, such is the inconsistant nature of C++.
 
J

Jef Driesen

Karl said:
Jef Driesen wrote:

[snip]
But what if I replace the data members with an array? Now I can only use
assignment in the constructor body:


Right.
That's because arrays are what we call 'half baked types'. Arrays behave
differently in many aspects then other types.

point::point(unsigned int x, unsigned int y)
{
m_data[0] = x;
m_data[1] = y;
}

My questions are:
(1) How is m_data initialized *before* the assignment in the body?


In this specific case: Not at all. int, unsigned int, char, float, double,
pointers (the 'builtin types') are *not* default initialized at all. They
simply contain what was in memory before the variable was placed there.
Usually its just garbage.

If you have an array of some class type however (eg. std::string), the default
constructor will be called for each array member.

(2) Will this result in lower performance?


Depends: If you have an array of builtin type, then no. Usually this won't
result in lower performance. If however the default constructor is run for
each array member, then yes, most likely this will result in lower performance.
It depends on what the default constructor has to do.

Thanks for the detailed answer.
 
J

Jef Driesen

Bob said:
POD-types are NOT default constructed or initialized, their value is
undefined. In order to default initialize an unsigned int, you must
write:

point::point(unsigned int x, unsigned int y)
: m_x(), m_y()
{
m_x = x;
m_y = y;
}

I didn't know I could default initialize a POD-type this way.
See my remarks above. You won't know until you have tested it.

(I believe it was Donald Knuth who said: "Premature optimization is
the root of all evil.")

I understand that, but I wanted to know what the compiler is actually
doing with the array. And I think it won't hurt to remove unnecessary
initializations if possible.
 
E

Edwin Fine, Fine Computer Consultants

OTOH, I don't know who originally wrote this, but "Belated
pessimization is the leaf of no good." :)

I hope I am not insulting your expertise and intelligence, but Herb
Sutter (http://www.gotw.ca) makes a very good argument for
internalizing practices that don't unnecessarily burden code with
"pessimizations" (in his and Andrei Alexandrescu's great book, "C++
Coding Standards : 101 Rules, Guidelines, and Best Practices").

Good examples of this would be using initializer lists to avoid
unwanted default constructions, and passing objects by reference to
avoid the unwanted cost of copying the objects. In no way can things
like this be construed as "premature optimization". It's simply good
C++ practice.

Of course, poring over every line of code to wring the last drop of
performance out of it, or replacing code with assembly language, before
knowing exactly where the real bottlenecks are, is genuine premature
optimization.
 
B

Bob Hairgrove

OTOH, I don't know who originally wrote this, but "Belated
pessimization is the leaf of no good." :)

I hope I am not insulting your expertise and intelligence, but Herb
Sutter (http://www.gotw.ca) makes a very good argument for
internalizing practices that don't unnecessarily burden code with
"pessimizations" (in his and Andrei Alexandrescu's great book, "C++
Coding Standards : 101 Rules, Guidelines, and Best Practices").

Good examples of this would be using initializer lists to avoid
unwanted default constructions, and passing objects by reference to
avoid the unwanted cost of copying the objects. In no way can things
like this be construed as "premature optimization". It's simply good
C++ practice.

Of course, poring over every line of code to wring the last drop of
performance out of it, or replacing code with assembly language, before
knowing exactly where the real bottlenecks are, is genuine premature
optimization.

I also use initialization lists as much as possible because I know
that it is good practice and avoids wasting work for objects with
non-trivial default constructors.

The OP was worried about the performance penalty from the extra
initialization of an unsigned int, though. It seemed to fit in with
your example: "... poring over every line of code to wring the last
drop of performance out of it".

(PS - I'll always be glad for anyone to "insult my intelligence" with
Herb Sutter's advice! <g>)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top