1

I'm reading classes tutorial in cplusplus.com.

I got confused by the following paragraph.

Default-constructing all members of a class may or may always not be convenient: in some cases, this is a waste (when the member is then reinitialized otherwise in the constructor), but in some other cases, default-construction is not even possible (when the class does not have a default constructor). In these cases, members shall be initialized in the member initialization list.

So, my question is what does the "when the member is then reinitialized otherwise in the constructor" mean? Why is a waste?

In the beginning, I think the "reinitialized` like following code.

class Son
{
    int age;

public:
    // default constructor
    Son()
    {
        age = 1;
    }

    Son(int age) : age(age) {}
};

class Father
{
    Son son;    // First, I think that it will call default constructor of class Son when the object of Father was created
    int age;

public:
    // Then object of Father will call this constructor, then initialize son again.
    Father(int sonAge, int fatherAge) : son(sonAge), age(fatherAge)
    {
    }

};

Then, I found Son son wasn't to define son at all, it just waited the constructor of Father to initialized son. So this isn't waste, my idea is wrong!!! Maybe I lack the knowledge of object creation order? cplusplus.com provides tutorial seems incomplete for me...

Can you give me a few code examples?

OnlyWick
  • 342
  • 2
  • 10
  • 1
    "reinitialized" is misleading. Each and every member is only initialized once, and that happens in the member init list of the constructor. If a member is not explicitly mentioned there, it will be default initialized. It may be *assigned* in the constructor body, and that's probably what the author meant. – Yksisarvinen Nov 04 '22 at 15:48
  • no such thing as reinitialisation. there are two different constructors here – Neil Butterworth Nov 04 '22 at 15:49
  • 2
    A member of a class can be initialised in the constructor initialiser list and then re-initialised (e.g. reassigned) in the constructor body. If you don't explicitly reference a member in the initialiser list then it is still default-initialised. The text is trying (in a clumsy way) to say that it's preferable to initialise each member once (i.e. in the initialiser list) rather than to initialise a member and then re-initialise. – Peter Nov 04 '22 at 15:51
  • @Peter that is assignment not initialisation - you simply cannot "re-initialise" anything – Neil Butterworth Nov 04 '22 at 15:52
  • @NeilButterworth Yes, I know. But it appears the text quoted in the question is [incorrectly] describing assignment (in the constructor block) as another form of initialisation. – Peter Nov 04 '22 at 15:54
  • also cplusplus.cpm is not the greatest resource – Neil Butterworth Nov 04 '22 at 15:54
  • ...But I read the [Other External Resources](https://stackoverflow.com/tags/c%2b%2b/info), so I think cplusplus.com may be a good resource.. In addition, I think I lack masive knowledge about c++ after I reading a few of the tutorial. – OnlyWick Nov 04 '22 at 16:00
  • 2
    cplusplus.com serves a purpose. It is dumbed down so that it is entry level reading. It's a good place to start, but when it leads you to more questions, or down a rabbit hole, I recommend switching over to cppreference.com and reading carefully to decipher the more correct and often much more complicated documentation. – user4581301 Nov 04 '22 at 16:10
  • Side note: Nothing I've seen online comes close to [a good set of books](https://stackoverflow.com/q/388242/4581301). for concentration of information and space available for well-thought-out explanation. – user4581301 Nov 04 '22 at 16:13
  • @user4581301 yeah, I try to read cppreference.com, but it is harder for me(lack of examples, but it describes knowledge very overall), I think it is unfriendly for beginner.. – OnlyWick Nov 04 '22 at 16:20
  • Every information source has a bar to entry, and the more complicated the information being presented, the higher the bar. C++ is very complicated. – user4581301 Nov 04 '22 at 16:26

2 Answers2

4

All objects are initialized before the body of the constructor is entered, so let's walk this through step-by-step:

int age;
Son() // age initialized here (does nothing)
{
    age = 1;// age assigned new value here
}

But what if age is something more complicated than an int? What if it is a class with very expensive construction?

Expensive age;
Son() // age initialized here takes a lot of time and resources
{
    age = 1;// age assigned new value here. This requires construction of a 
            // temporary Expensive (which takes a lot of time and resources)
            // and then assigns the temporary to age (which may also be time and 
            // resource-consuming), wasting the effort spent on the default 
            // construction. The temporary is then destroyed, and that wastes 
            // even more
}

If you use the Member Initializer List

Expensive age;
Son(): age(1) // age initialized here takes a lot of time and resources
{
    // does nothing
}

Note: The above is a worst-case example. Expensive could have an Expensive &operator=(int) that shaves off some of the work, but you still need to deal with default construction and the assignment logic in place of a single constructor call. Plus someone had to write the = overload, and code that doesn't exist has no bugs.

user4581301
  • 33,082
  • 7
  • 33
  • 54
  • Why is it faster to use the Member Initializer List? – OnlyWick Nov 04 '22 at 16:15
  • More stuff happens if you assign anything complicated inside the body. One constructor call for the member, if you use the initializer list, rather than (probably) two constructor calls, a call to an assignment operator and (probably) a call to a destructor. – user4581301 Nov 04 '22 at 16:18
  • As user17732522 points out in their answer, a good compiler may spot what you are doing and eliminate most of the work as redundant ([see the as-if rule](https://en.cppreference.com/w/cpp/language/as_if)), but it can't always do this. Sometimes you just have to write smarter code. – user4581301 Nov 04 '22 at 16:23
3

So, my question is what does the "when the member is then reinitialized otherwise in the constructor" mean?

There is no such thing as "reinitialization". Every object is initialized exactly once (although that initialization may be vacuous, meaning it doesn't actually do anything; also there is zero-initialization before actual initialization in certain cases, which may be considered two initializations). What the author intents this to mean is assignment after the initialization.

In your example this happens with the constructor

Son()
{
    age = 1;
}

This constructor has no member initializer, meaning that the member age (which doesn't have a default initializer in its declaration either) will be default-initialized. Only after the initialization is the body of the constructor executed and the assignment age = 1; done.

Now in this case there is basically no waste because default-initialization of an int does not do anything (it leaves the value indeterminate). However imagine age was a std::string and the assignment was age = "1"; instead. Then you would first call the default constructor of std::string to initialize age and then later you would assign "1" to age. The first step is redundant and using an initializer list Son() : age("1") { } would avoid that extra step. (Whether or not there will actually be any performance difference depends on many factors and the compiler may just be good enough to optimize both to the same machine code.)

One issue with the word "intialization" is that it is colloquially often used differently from the technical meaning described above. Colloquially it may refer to the first time a variable has its value set. In this case the assignment age = 1; would be considered to initialize age, although that is assignment, not initialization. This meaning is most often used when talking about a variable being uninitialized, which more technically correct should be being of indeterminate value.

user17732522
  • 53,019
  • 2
  • 56
  • 105