Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do these two C++ initializer syntaxes ever differ in semantics?

Assume that the following code is legal code that compiles properly, that T is a type name, and that x is the name of a variable.

Syntax one:

T a(x);

Syntax two:

T a = x;

Do the exact semantics of these two expressions ever differ? If so, under what circumstances?

If these two expressions ever do have different semantics I'm also really curious about which part of the standard talks about this.

Also, if there is a special case when T is the name of a scalar type (aka, int, long, double, etc...), what are the differences when T is a scalar type vs. a non-scalar type?

like image 716
Omnifarious Avatar asked Feb 21 '11 09:02

Omnifarious


3 Answers

Yes. If the type of x is not T, then the second example expands to T a = T(x). This requires that T(T const&) is public. The first example doesn't invoke the copy constructor.

After the accessibility has been checked, the copy can be eliminated (as Tony pointed out). However, it cannot be eliminated before checking accessibility.

like image 163
MSalters Avatar answered Oct 19 '22 18:10

MSalters


The difference here is between implicit and explicit construction, and there can be difference.

Imagine having a type Array with the constructor Array(size_t length), and that somewhere else, you have a function count_elements(const Array& array). The purpose of these are easily understandable, and the code seems readable enough, until you realise it will allow you to call count_elements(2000). This is not only ugly code, but will also allocate an array 2000 elements long in memory for no reason.

In addition, you may have other types that are implicitly castable to an integer, allowing you to run count_elements() on those too, giving you completely useless results at a high cost to efficiency.

What you want to do here, is declare the Array(size_t length) an explicit constructor. This will disable the implicit conversions, and Array a = 2000 will no longer be legal syntax.

This was only one example. Once you realise what the explicit keyword does, it is easy to dream up others.

like image 27
Pianosaurus Avatar answered Oct 19 '22 18:10

Pianosaurus


From 8.5.14 (emphasis mine):

The function selected is called with the initializer expression as its argument; if the function is a constructor, the call initializes a temporary of the destination type. The result of the call (which is the temporary for the constructor case) is then used to direct-initialize, according to the rules above, the object that is the destination of the copy-initialization. In certain cases, an implementation is permitted to eliminate the copying inherent in this direct-initialization by constructing the intermediate result directly into the object being initialized; see class.temporary, class.copy.

So, whether they're equivalent is left to the implementation.

8.5.11 is also relevant, but only in confirming that there can be a difference:

-11- The form of initialization (using parentheses or =) is generally insignificant, but does matter when the entity being initialized has a class type; see below. A parenthesized initializer can be a list of expressions only when the entity being initialized has a class type.

like image 2
Tony Delroy Avatar answered Oct 19 '22 17:10

Tony Delroy