Philosophic reason for initializing members as apposed to initialization function??

OK gang,

Back for more questions and I did look this up FIRST but was unable to really match a correct answer. Maybe I didn't understand it even though I saw it??

So in the good Dr's book (chapter 9 of "Principles and practices..." section 9.7.3) [I feel like I'm quoting chapter and verse here people! LOL!]

We are essentially given good advice to initialize EVERYTHING and especially classes' members upon instantiation! So far so good...makes sense..... but he then shows TWO different ways of doing this and I am trying to understand from a philosophical (and practical??) reason between these two and why the later would be "superior" if not slightly more convoluted==>

1.) Initialize the members as "in-class initializers" in the member declaration INSIDE the definition code itself

AS OPPOSED TO....

2.) Making a separate function whose SOLE purpose is to return a constant <type> reference to a STATIC pre-defined generic of this type with the initializers built into this function instead. (Yeah, WTH is right! Try thinking how to express THAT from a beginner's stand-point of view!)

From what I can tell, the ONLY way this really makes things easy and cool is if you were making a large vector of this type such that all the vector elements would be immediately set to this pre-defined initialized state in an implicit manner?? (or woudld it??)

Let me expound in code version===>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//Method #1 from above (seems straight forward and logical...)
  
class something{  //definition of class and members initialized
   public:  (. . . )

   private:

   int x{4096};  //members are initialized inside class upon 
   int y{512};   //instantiation of a something object.... right?
   int z{65536};  
}


//Method #2 from above (not sure why this makes #1 not as "cool"..??)

const something& default_something(){

   static something my_thing{4096, 512, 65536};  //static is a one-time 
   return my_thing;                              //definition in compiler??

}

// which is then used like such....

something::something()  //new default constructor of a "something" object...
   :x{default_something().x}, y{default_something().y}, z{default_something().z}

{
  //body of constructor IF anything but empty....
}


Now call me a moron but what REALLY did all that extra mumbo-jumbo (forgive me Dr. Stroustrup...) really do for me in the long run that I suppose I really just don't get at the moment??

Any takers??

Xanadu
Taking a peek at that book, he doesn't seem to be saying it's necessarily much better. I can see only two advantages:

1. In constructing the static default date with the ctor that takes three values, that ctor can check
    that the values are within constraints. Therefore we know we are safe to assign those values
    directly to member variables in the default ctor.

2. You can easily reassign the default value to an object.
Last edited on
I agree with @dutch, I don't see Stroustrup said anything about it being better, but he shows an evolution of thought about preference along the way of dealing with default values.

In the book's example there's one point not illustrated in your example, @Xanadu4ever, where there are limits placed on the parameters (a month can't exceed 12, a day should be qualified by the month (and year), etc).

That's not much of an impact itself, and doesn't change your question, but it does clarify that one point where the parameters to the various constructors may require checking or limitation, which he illustrates by making a "Month" type enumeration (instead of an int).

He "evolves" the example of the default constructor for "Date" by first showing the default parameters as part of the constructor with:

Date::Date() : y{2001}, m{Month:jan}, d{1}{}

Then expresses and alternative matching your first form, placing the defaults within the class declaration.

He then illustrates how this can apply to multiple constructors (and I think this is key to the evolution he's following), such that a partial specification is possible, like:

Date::Date(int y) :y{yy}{}

Though he checks for validity, he's pointing out that the defaults for month and day would be from the defaults while the year is provided from the user (and, obviously, the other permutations might apply).

Then he introduces the second form with:

1
2
3
4
5
const Date& default_date()
{
  static Date dd{2001, Month:jan, 1};
  return dd;
}


...and then his commentary strikes a chord in my mind:

We used a static...that is created only once....initialized the first time default_date() is called


To me, this is key. He's avoiding a global value. Consider the case of dynamic library code where it is key to be able to initialize once after the process is running, as in lazy initialization when the default code is called.

Although he doesn't explicate this is his intention (I'm not sure the subject of dynamic library code is even discussed), it is more generically associated with the avoidance of global variables (as defaults), which he merely references problematic.

Also, he does introduce the second form with a clause about preference, "If we didn't like to build the default value right into the constructor code"...which then leads to this second form as the avoidance of global variables (and their associated initialization problems).

This leads to other examples where this static default value is accessible to user code as well as the constructor permutations.
Last edited on
Ok Dutch and Niccolo,

I think I see what you are saying - so the advantage of the "default form" (second version that is) allows me to 1.) avoid global variables and 2.) I can easily reassign instantiated objects for any reason this way and finally 3.) the static default version is now accessible to all user code as well as the member constructors?

To this last point ==> it allows us to use it like it was global AND the class members can use it too and so "everyone" is happy and it is versatile. Is that the main take away I'm supposed to get here or am I still not getting the fine nuances of this??

Do both of you guys use this "second form" of initialization on a regular basis in your coding to be able to avoid global variables and yet have the class use this as well along with anything else that wanted to use it?

Xanadu
@Dutch might notice something, but my quick read is "yes", you got it.

I do choose the "second form" in a number of circumstance, and it so happens it was an important technique in recent work where I'm "forced" to write dynamic libraries with what "might" be simple with a bunch of global variables that aren't simple built in types and can't be instantiated as defaults with constexpr's or other means.

I don't reach for it automatically. The "Date" example by Stroustrup is about the absolute minimal example where I'd choose it (which is his way - absolute minimal example).
Topic archived. No new replies allowed.