Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When it make sense to replace "class_name obj_name = func()" by "class_name obj_name{func()}"?

In a code I see the following construct:

const class_name obj_name{func()};

func() return an object of the class called class_name. So, I wonder why not to use the following construction:

const class_name obj_name = func();
like image 662
Roman Avatar asked Apr 02 '13 08:04

Roman


2 Answers

const class_name obj_name{func()};

By writing the above, the author is trying to follow uniform initialization syntax (introduced by C++11), so as to avoid problems caused by vexing parse and most vexing parse, into which even experienced programmers get trapped accidently. He is trying to inculcate the best practice into his brain so that he doesn't get trapped into the said parsing issues occasionally as explained below.

Consider this,

struct X { /*....*/ }; // some class

struct Y 
{
    Y();
    Y(int i);
    Y(X x);
};

Now one can write this:

Y y(100); // declare an object y of type Y

that invokes the second constructor, which is fine. So far, so fine!

But accidently one even write this:

Y y(); 

(mistakenly) thinking that it invokes the default constructor. But the fact is that it doesn't invoke the default constructor. It instead declares a function y which takes no argument, and returns Y. That is called vexing parse in C++.

Likewise, one can write this (accidently),

Y y(X());

thinking that it invokes the third constructor passing an object of type X which is created on the fly. Again, it is wrong. It instead declares a function y which takes a function pointer (of type function which takes nothing and return X) and return Y. It is called most vexing parse in C++.

So uniform initialization syntax avoids all such issues, you can write this:

Y y1{};      // invokes 1st constructor
Y y2{100};   // invokes 2nd constructor
Y y3{X{}};   // invokes 3rd constructor

and following the same syntax,

Y { function_call() }; 

const class_name obj_name { func() }; // taken from your question!

That is uniform and certainly best practice, isn't?

Hope that helps.

like image 118
Nawaz Avatar answered Nov 09 '22 23:11

Nawaz


As of C++11 the uniform initialization feature was introduced which provides several ways to initialize types.

In this case, both syntaxes will call the class_name(class_name const&) copy constructor (if one exists). Therefore there's no real difference. It just a matter of preference.

It is to note that the {} syntax don't always behave like in this case: if there is an initialization_list constructor of the appropriate type, that constructor is used, otherwise the class elements are initialized using the appropriate constructor.

In cases where the Most Vexing Parse principle (if it can possibly be interpreted as a function prototype, then it will be) strikes you are required to use either one of the two to tell the compiler that the following is not a function prototype:

typename class_name obj_name(func());
class_name obj_name { func() };
like image 26
Shoe Avatar answered Nov 10 '22 00:11

Shoe