Different ways of initializing an object in c++

The difference in initialization lies not only in form it takes, but also
in type of entity which is being initialized. In this case it’s a class-type object with a defined default constructor, as well as a constructor with parameters.

Entity ent1;  

The statement above is default initialization which result in a call of default constructor for the class Entity.


Entity ent2();

The declaration above will be treated by compiler as a function prototype if that’s possible. Entity would be returned type of a function ent2, which takes no arguments. It’s known as a case of most vexing parse (MVP) and its existence led to appearance of misleading “clever dumb rule”: “never use parenthesis”.


In statement like this a user-defined constructor that matches list of arguments is invoked for ent3 object:

Entity ent3(1, 2);    // calls Entity(int x, int y)

Another case where MVP can strike is something like this:

Entity ent3_1(int(a), int(b));  // It's not what it looks like.

ent3_1 above is not a variable. The statement declares a function with two int parameters. int(a) being same as int a is legacy of C language and declaration syntax there, which ignores “extra” parenthesis.


Entity ent4 = Entity();

ent4 is a proper version of ent2 case until C++11. Default constructor is invoked as part of value initialization. Its form allows to avoid an ambiguity solving principle which makes ent2 and ent3_1 incorrect. Equal sign here is not an assignment, for no operator= call will happen here. It’s part of declaration syntax meant to markup the initialization expression.


Entity ent5 = Entity(2, 3);

ent5 is a version of ent3 case. User-defined constructor invoked as part of value initialization.


Your question is tagged as C++11, and C++11 allows uniform initialization syntax:

Entity ent12{};     // This is a legal alternative of ent2 case
Entity ent13{1, 2}; // A call to constructor or member initialization
Entity ent13{ int(a), int(b) }; // Not a function anymore
Entity ent14 = {};              // Not an assignment
Entity ent15 = Entity{2, 3};    // Not an assignment either!

Note that uniform initialization syntax has a caveat. E.g. this line

std::vector<int> v(10); 

declares a vector of 10 elements. But this one

std::vector<int> v{10};

declares a vector initialized with single element of type int with value 10. This happens because std::vector has a constructor with following signature defined:

vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );

In case that you can’t use neither () without triggering MVP nor {} without invoking undesired constructor, the value initialization assignment syntax allows to resolve the issue.

Addendum: Must watch CppCon 2018: Nicolai Josuttis “The Nightmare of Initialization in C++”

Leave a Comment