Yue Wang
Yue Wang

Reputation: 1750

What will happen if a user defined constructor omits initialization for data members?

Suppose:

class Foo
{
public: 
    Foo();
    Foo(typeA a);
private:
    typeB b;
    typeC c;
};

Foo::Foo(typeA a)
{
    //do something with a, but nothing with b nor c.
}

int main()
{
    typeA a;
    Foo foo(a);
    return 0;
}

What will happen here? Are foo.b and foo.c default initialized? Is it a good practice to define a constructor this way?

Upvotes: 3

Views: 260

Answers (3)

Emilio Garavaglia
Emilio Garavaglia

Reputation: 20730

Well... it's not always a good practice essentially because the effect become visible later when the object will be used.

The point of a constructor is to "construct" something so that it can be safely used, and hence it must be finished.

The problem of leaving b and c untouched will exhibit a different behavior depending it typeB and typeC are user types or built-in types.

Buitin types requires construction to be explicit (otherwise will contain "random" values). User types are always default constructed (note that the problem is recursive: if the user types contains a builtin type and does not initialize it, its' default construction will let the builtin type uninitialized).

So, if typeB and typeC are generic (template parameter or calculated from template parameters) and can be builtin types, initialization is a must... unless you admit the resulting object is "valid" even with random values for some members (what does it mean, depends on the semantic of your object)

If typeB and typeC are known user types and have complete initialization from their own default ctors, than you can avoid the explicit call (since it will be done implicitly)

Note that -in C++11- you can specify the initialization of members in the member declaration, rather than construction:

class Foo
{
public: 
    Foo();
    Foo(typeA a);
private:
    typeB b = 5; //<---- note this!
    typeC c = 7; //<---- note this!
};

This will let all the constructors to find those values, unless differently initialized by specific initializer lists. In practice a sort of "default of defaults".

If types are generic, is not infrequent to explicitly initialize them by providing an empty initializer:

template<class T>
class wrapper
{
    T m = {} //<---- note the empty {}
public:
    wrapper() {}
    wrapper(T&& t) :m(std::forward<T>(t)) {}
    wrapper(const wrapper& s) :m(s.m) {}
    wrapper(wrapper&& s) { swap(s); }
    wrapepr& operator=(wrapper s) { swap(s); return *this; }
    ~wrapper() { /* cleanup m */ }
    void swap(wrapper& s) { std::swap(m,s.m); }
};

Upvotes: 2

juanchopanza
juanchopanza

Reputation: 227418

Are foo.b and foo.c default initialized?

Yes, the data members will be implicitly default-initialized. But what default initialization does depends on the type of the object being initialized. For user defined types, this means their default constructor will be called. For built-ins or PODs, this means no initialization will be performed. So it depends on that typeA and typeB are:

If they are user defined types, their default constructor will be called. If they are built-ins or PODS, no initialization will be made.

Is it a good practice to define a constructor this way?

Assuming you have data members of user defined types, that is more a matter of convention and coding standards. I have seen it argued both ways: on the one hand, why explicitly value initialize data members if value initialization and implicit default initialization do the same thing (as with user defined types)? It could be argued that you don't know what you are doing. On the other hand, why not be explicit about everything? What if you change a data type from a user defined type to a built-in and forget to add it to the constructor's initialization list? I tend to be on the "I know what I am doing" side of the argument, but that is purely personal.

In the case where your data members are built-ins or PODs, then it really boils down to the requirements of your own code: do you want to zero-initialize the members or not? Usually you do, but this initialization does not come for free and it may matter is some cases. This is the reason these types do not get zero initialized by default in C++. So, again, there is no clear answer, but in most real code I have dealt with you do want members to be zero-initialized.

Upvotes: 9

Anil Kumar
Anil Kumar

Reputation: 488

Entirely dependant on what exactly are

type B & type C.

If they are primitive/built-in type, they won't be initialized. Otherwise, for derived types, they will be default-initialized.

Upvotes: 0

Related Questions