4

What's the difference between these two declarations of constructors:

class Fruit { private: int price; public: Fruit(int x): price(x) { } }; 

VS

class Fruit { private: int price; public: Fruit(int x) { price = x; } }; 

The first one I have seen in case of inheritance.

As per my knowledge, this is not a duplicate question. If you find one feel free to close this question.

1
  • Both will not compile, though, unless you add a ; after the declaration: int price; Commented Nov 10, 2018 at 23:04

4 Answers 4

8

The first one initialize price with x where the second one initialize price with its default value (default construct it; in case of a int variable, is initialized with an undefined value) and then copy x in price.

In other words, the first one is almost equivalent to

int price = x; 

where the second one is almost equivalent to

int price; price = x; 

In case of a int variable (taking also in count the compiler's optimizations) I suppose there isn't an effective difference.

But when price is a complex object, with an heavy construction cost, there can be a great difference.

As better explain Peter, "It's not construction cost that makes the difference between the two for complex objects. It is a question of whether reassigning after default initialisation is more costly than initialising in one step. Practically, the two stage process is often more expensive (by various measures) than direct initialisation, since it can be necessary to clean up the default setting in order to change the value. There are also concerns of exception safety - what if reassignment or construction throws an exception."

So, usually, is strongly suggested to use the first solution (initialize the object with the right value).

See also the Zereges's answer that point the attention over the fact that the first one method is the only available to assign a value to a constant member.

Indeed you can't write

int const price; price = x; // error: price is const 
Sign up to request clarification or add additional context in comments.

4 Comments

Might be worth noting that for user-defined types the second option calls default constructor and that might not be no-op like int price;.
Oh, you just added it :)
It's not construction cost that makes the difference between the two for complex objects. It is a question of whether reassigning after default initialisation is more costly than initialising in one step. Practically, the two stage process is often more expensive (by various measures) than direct initialisation, since it can be necessary to clean up the default setting in order to change the value. There are also concerns of exception safety - what if reassignment or construction throws an exception.
@Peter - I was trying to explain this point but your explanation if far more clear than mine. I've simply copied it. Thanks.
6

The first one uses an initialization list, while the other doesn't, and assigns x to the data member price inside the body of the constructor.

We usually prefer to use initialization lists, and to keep the body of the constructor as simple as possible.

4 Comments

It is unfortunate that initialization-lists' syntax is somewhat ugly and precludes the use of intermediate rvalues.
Indeed @Dai, but still useful!
This is not correct. It is not possible to "initialise a data member inside the body of the constructor". That is an assignment.
@LightnessRacesinOrbit good catch, corrected, thanks!
4

To add up to other answers, the first option is the natural way to initialize const members

struct C { const int val; C() : val(5) // Perfectly OK { } C(int) // error: uninitialized const member in 'const int' [-fpermissive] { val = 5 // error: assignment of read-only member 'C::val' } }; 

Also, when class has members of type, that are not default-constructible, this is the way to initialize them

struct D { struct not_default_constructible { not_default_constructible(int) { } } var; int& ref; D(int a) : ref(a), var(5) // Legal { } D(int a, char) // error: uninitialized reference member in 'int&' [-fpermissive] { // error: no matching function for call to 'D::not_default_constructible::not_default_constructible()' ref = a; } }; 

1 Comment

Similarly, a member of class type, when that class does not have an accessible default constructor, can only be initialized using the mem-initializer-list.
3

The second one does not initialize price with x when a Fruit is created which therefor default constructs it. Just as if you'd written:

class Fruit{ private : int price public: Fruit(int x) : price() // default constructed { price = x } } 

For effectiveness, it's better to initialize with the value you want to assign to it.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.