Different Ways of Initializing an Object in C++

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++”

Initializing an object with and without new operator

Rectangle *Obj;

just defines a pointer to an object of class Rectangle. Defining a pointer does not reserve any memory for the object itself, just for the pointer. Thus, if you access the pointer, you will likely end up at an address in memory that doesn't even belong to your process. However, the compiler cannot know that you haven't initialized the pointer (the keyword here is aliasing) and hence cannot output an error message.

The solution is either using new like you suggested, or declare an instance of Rectangle like so:

Rectangle Obj;

which will call a default constructor. You can then set your members using

Obj.Set(3, 5);

Different methods for instantiating an object in C++

The second is wrong !

You may use

MyClass object;

That will work.

Now, concerning how to choose between these two possibilities, it mainly depends on how long your object should live. See there for a thorough answer.



Related Topics



Leave a reply



Submit