Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between constructor calls with and without ( )

Tags:

I'm a C++ beginner and would like to understand why

return std::list<int>(); 

needs parentheses, but

std::list<int> foo; 

doesn't need parentheses. What's the difference between these constructor calls?

like image 211
user3561614 Avatar asked Oct 12 '15 11:10

user3561614


People also ask

Can constructor be called without object?

Dr. Bjarne: No. temporary objects of the class types are useful.

What is difference between constructor and normal member function?

A constructor is a member function of a class that is used to create objects of that class. It has the same name as the class itself, has no return type, and is invoked using the new operator. An ordinary member function has its own name, a return type (which may be void), and is invoked using the dot operator.

What is the difference between class and constructor?

in simple words a class is like a blueprint and defines the framework that other objects can inherit, a constructor is something that actually creates the object in the program whereas the class only gives the guidelines.


1 Answers

Neither of these are constructor calls.

The first is an explicit type conversion, which creates an object of type std::list<int>.

The second is a variable definition which creates an object of type std::list<int>.

The default-constructor (constructor taking no arguments) is called as part of the creation in both cases.

Although you might see such things talked about as "constructor calls", there's no syntactic construct to explicitly and singularly call a constructor in C++.

The reason one needs parentheses when the other doesn't is because they are two separate language constructs with different syntax rather than two ways to call a constructor.


Note that if you add parentheses to your second example, you actually declare a function rather than defining a variable:

std::list<int> foo; //variable definition std::list<int> foo(); //function taking no args, returning a std::list<int> 

This is commonly known as the most-vexing-parse. C++11 introduced braced-initialization to get around this:

std::list<int> foo{}; //variable definition 

The Standardese, for those so inclined

(Quotes from N3337)

"But T() sure looks like a constructor call, why is it not?"

In that context, T() is known as an explicit type conversion with functional notation:

5.2.3 Explicit type conversion (functional notation) [expr.type.conv]

1 [...]

2 The expression T(), where T is a simple-type-specifier or typename-specifier for a non-array complete object type or the (possibly cv-qualified) void type, creates a prvalue of the specified type, which is value-initialized (8.5; no initialization is done for the void() case). [Note: if T is a non-class type that is cv-qualified, the cv-qualifiers are ignored when determining the type of the resulting prvalue (3.10). —end note ]

So this creates a prvalue which is value-initialized.

[dcl.init]/7: To value-initialize an object of type T means:

if T is a (possibly cv-qualified) class type (Clause 9) with a user-provided constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);

— [...]

So this calls the constructor as part of the value-initialization, which is part of an explicit type conversion. As stated above, there is no way to call a constructor directly. The standard says:

[class.ctor]/1: Constructors do not have names. A special declarator syntax is used to declare or define the constructor. The syntax uses:

— an optional decl-specifier-seq in which each decl-specifier is either a function-specifier or constexpr,

— the constructor’s class name, and

— a parameter list

in that order. In such a declaration, optional parentheses around the constructor class name are ignored.

So constructors don't have names and we declare/define them with a syntax exception which the language defines.

"This seems like an academic distinction, does this matter in practice?"

Maybe, maybe not. My opinion is that interpreting syntax like the above as pure constructor calls paints an incorrect picture of what a constructor is. A constructor initializes an object; it doesn't allocate that object's memory, return the initialized object, bind a symbol to that object or anything else which is done by variable definitions and type conversions. Furthermore, it can create confusion like that of the OP, who expected uniform syntax because he thought those two constructs are both constructor calls.

Why use inexact synecdoche when we have formal terms which avoid confusion?

like image 94
TartanLlama Avatar answered Oct 04 '22 04:10

TartanLlama