Constructor initialization

2019-08-02 08:54发布

问题:

I am reading "Accelerated C++" by Andrew Koenig and Barbara E. Moo, and I'm at the chapter about constructors (5.1).

They mention here that

We said that constructors exist to ensure that objects are created with their data members in a sensible state. In general, this design goal means that every constructor should initialize every data member. The need to give members a value is especially critical for members of built-in type. ...

Although we explicityly initialized only midterm and final, the other data members are initialized implicitly. Specifically, n is initialized by the string default constructor, and homework is initialized by the vector default constructor.

The class they are talking about is

class Student_info {
public:
    std::string name() const (return n;}
    bool valid() const {return !homework.empty();}
    std::istream& read(std::istream&);

    double grade() const;
private:
    std::string n;
    double midterm, final;
    std::vector<double> homework;
};

and their default constructor is

Student_info::Student_info(): midterm(0), final(0) {}

I would just like to clarify that this means that things like int and double where there isn't a std:: before the term will need to be initialized specifically?

回答1:

That is correct.
But std:: is not what you are looking for.

Any of the fundamental types are not initialized unless you do it explicitly.

So char/int/float/pointers etc. Also (as noted by Ian below) any class/unions without an explicit constructor will default initialize its members (which means fundamental (and recursively for member s of class/unions without and explicit constructor) that they are left undefined).

A side note:

  • This rules applies to automatic and dynamic storage duration objects
  • Static and thread storage duration objects are zero initialized.


回答2:

int and double are built-in types, not classes, so they don't have default constructors, and are undefined by default. For example:

int a;
Student_info s;

The syntax for both variables is the same, but the value of a is undefined, while the value of s is defined because Student_info s actually calls the constructor, i.e. Student_info s = Student_info();.



回答3:

The author is just trying to show a default constructor where everything is defaulted to the equivalent of 0. For string and vector, those will just be empty. For primitive types such as int and double, the initial value of these primitives during declaration is defaulted to the value that was in memory that variable points to. This does depend on the compiler though



回答4:

It is not related to std namespace. n and homework are classes, their constructor will be called during the construction of Student_info. But midterm and final are primitive values, there aren't constructors for them. Initialize the primitive member in constructor is not necessary but a good manner.



回答5:

There is more to it.

1) For primitive or built-in types, implicitly initialized (or compiler initialized) means no-op (does nothing).

2) For primitive or built-in types, explicitly initialized (or initialized by the programmer) is obvious :)

As in your example:

    Student_info::Student_info(): midterm(0), final(0) {}

3) For non-primitive types, implicitly initialized (or compiler initialized) means compiler may (or may not) synthesis a constructor for the purpose of initialization.

 Usually, a constructor is synthesized by the compiler under the following cases:

 a) The non-primitive type is polymorphic or derives from some polymorphic/non-polymorphic types,
 b) The non-primitive type has a polymorphic/non-polymorphic member. 

 Compiler synthesized constructor will usually have code to 

 a) initialize v-pointer to v-table, 
 b) call base class constructor, 
 c) call constructors of members, so on, 

 basically driven by the definition of non-primitive type.

4) For non-primitive types, explicitly initialized (or initialized by the user supplied constructor) means compiler would make a call to the user defined constructor instead of synthesizing one for the purpose of initialization.

For example, the default constructor defined by the respective non-primitive types (like std::string or std::vector) gets invoked.

**

Note: Compiler may still augment code inside the user-defined constructor to do some behind-the-scenes initialization as need be (look at step-3 above for such needs). Such augmented code will always be inserted before the user-defined code inside the constructor!

**