views:

325

answers:

4

Will the initialization list always be processed before the constructor code?

In other words, will the following code always print <unknown>, and the constructed class will have "known" as value for source_ (if the global variable something is true)?

class Foo {
  std::string source_;
public:
  Foo() : source_("<unknown>") {
    std::cout << source_ << std::endl;
    if(something){
      source_ = "known";
    }
  }
};
+5  A: 

Yes, it will (short and to the point).

UPDATE (not so short :-):

The main reason for using init-lists is to help the compiler with optimization. Init-lists for non-basic types (i.e., class objects rather than ints, floats, ...) can generally be constructed in-place.

If you create the object then assign to it in the constructor, this generally results in the creation and destruction of temporary objects, which is inefficient.

Init-lists can avoid this (if the compiler is up to it, of course - most of them should be).

The following complete program will output 7 but this is for a specific compiler (CygWin g++) so it doesn't guarantee that behavior any more than the given sample. However, the feature would be less-than-useful if it were no defined by the standard.

#include <iostream>
class Foo {
    int x;
    public:
        Foo(): x(7) {
            std::cout << x << std::endl;
        }
};
int main (void) {
    Foo foo;
    return 0;
}

The latest ("2800", December 2008) draft C++ standard is available as N2800 from here. This document (or its replacement once it leaves draft status) is the final arbiter in any C++ standards discussion (I don't have the interest to search this document so I'll leave it to others who are more inclined :-).

paxdiablo
I like these questions, they're very easy to answer. My original answer was just "Yes" but SO wouldn't accept it since it was too short :-)
paxdiablo
Makes me wonder why people just don't try to compile the source first though :)
arul
@arul: @dehmann may only have the one compiler. If that behavior is of implementation-defined, compiling won't help. You'd need to refer to the standard.
paxdiablo
Yes, just compiling and trying out doesn't tell you if that will work the same everywhere.
One reason why I asked the question was that I seem to remember that in the constructor I should refer to the constructor arguments, but not the member vars that just have been initialized, as in: Foo(std::string str) : str_(str) { // now refer to str rather than str_}. But it seems that's wrong.
Your long version leaves me confused. With the "output 7" example you give an example similar to the one I had given, and you say it will output 7, but only for specific compilers, and it's not guaranteed?
I always use the smallest full program for testing and I didn't say it wasn't guaranteed, just that I only tested it on one compiler. You'll need to look into the latest standard that I linked to, to confirm that it specifies that behavior - I believe the original did.
paxdiablo
I don't agree on optimizations being the main reason for initialization lists, but rather construction of bases and members that cannot be default constructed (whose types require parameters to the constructor). It is a too complex discussion to handle just in the comments section. Won't up/downvote
David Rodríguez - dribeas
Well, they can be optimized better since they can be done in-place at construction time (of the member in the init-list, not the object containing it). Using assignment in the constructor of the containing object, you first create a default member then copy-construct it. So while ...
paxdiablo
... it may not be the main reason, it is certainly a valid reason. It's certainly the main reason I ever used it. And you could just as easily create non-default-constructor members in the constructor of the containing object rather than the init-list.
paxdiablo
That is only a side effect. The member attributes are initialized (or not, depends on the type) _before_ entering the constructor block. If a member attribute is a POD and does not appear in the initialization list, then no extra work is performed by the compiler. Space is reserved but not ...
David Rodríguez - dribeas
... initialized, so there is no real performance advantage. Only for types that do provide a default constructor the member attribute is initialized first in the initialization list and then assigned in the block.
David Rodríguez - dribeas
+5  A: 

Yes, C++ constructs all the members before calling the constructur code.

lothar
+1  A: 

In case you want to go deep into initializer list.

aJ
I actually read that right before asking the question. I don't think it's answered there.
+2  A: 

As already answered, initialization lists get completely executed before entering the constructor block. So it is completely safe to use (initialized) members in the constructor body.

You have made a comment in the accepted answer about having to refer to the constructor arguments, but not the member vars inside the constructor block. You don't.

It is possible that you mistook the fact that you should refer to parameters and not to member attributes inside the initialization list. As an example, given a class X that has two members (a_ and b_) of type int, the following constructor may be ill-defined:

 X::X( int a ) : a_( a ), b( a_*2 ) {}

The possible problem here is that the construction of the elements in the initialization list depends on the order of declaration in the class and not the order in which you type the initialization list. If the class were defined as:

class X
{
public:
   X( int a );
private:
   int b_;
   int a_; 
};

Then, regardless of how you type the initialization list in, the fact is that b_( a_*2 ) will be executed before a_ is initialized since the declaration of the members is first b_ and later a_. That will create a bug as your code believes (and probably depends) on b_ being twice the value of a_, and in fact b_ contains garbage. The simplest solution is not refering to the members:

 X::X( int a ) : a_( a ), b( a*2 ) {} // correct regardless of how X is declared

Avoiding this pitfall is the reason why you are suggested not to use member attributes as part of the initialization of other members.

David Rodríguez - dribeas