Are () and {} always equivalent when used to initialize with the "new"?

When using a new message, there is a column in parentheses or not after the type name . But what about this:

If "Test" is a regular class, is there a difference between:

Test* test = new Test(); // and Test* test = new Test{}; 

Also, suppose Test2 has a constructor for an argument of type Value , whether it is always equal to the record:

 Value v; Test2 *test2 = new Test(v); // and Test2 *test2 = new Test{v}; 
+7
c ++ constructor initialization new-operator c ++ 11
source share
3 answers

In contexts, there may be a difference in std::initializer_list<> , for example:

Case 1 - () and {}

 #include <initializer_list> #include <iostream> using namespace std; struct Test2 { Test2(initializer_list<int> l) {} }; int main() { Test2* test3 = new Test2(); // compile error: no default ctor Test2* test4 = new Test2{}; // calls initializer_list ctor } 

Case 2: (v) and {v}

 struct Value { }; struct Test3 { Test3(Value v) {} Test3(initializer_list<Value> v) {} }; int main() { Value v; Test3* test5 = new Test3(v); // calls Test3(Value) Test3* test6 = new Test3{v}; // calls Test3(initializer_list<Value>) } 

As stated by Meyers and others, there is also a huge difference when using STL:

  using Vec = std::vector<int>; Vec* v1 = new Vec(10); // vector of size 10 holding 10 zeroes Vec* v2 = new Vec{10}; // vector of size 1 holding int 10 

and not limited to std::vector only

In this case, the difference does not exist (and initializer_list ctor is ignored)

 #include <initializer_list> #include <iostream> using namespace std; struct Test { Test() {} Test(initializer_list<int> l) {} }; int main() { Test* test1 = new Test(); // calls default ctor Test* test2 = new Test{}; // same, calls default ctor } 

There is also a known difference in this case.

 void f() { Test test{}; Test test2(); } 

where test is the default initialized object of type test , and test2 is the function declaration.

+9
source share

Not!

The new initializer can take the following forms:

new initializer:
( opt list expression )
prepared-init-list

and

[C++11: 5.3.4/15]: A new expression that creates an object of type T initializes this object as follows:

  • If the new initializer is omitted, the object is initialized by default (8.5); if initialization fails, the object has an undefined value.
  • Otherwise, the new-initializer is interpreted in accordance with 8.5 initialization rules for direct initialization.

and

[C++11: 8.5/15]: Initialization that occurs in forms

 T x(a); T x{a}; 

as well as the expressions new (5.3.4), static_cast (5.2.9), type conversion of functional notation (5.2.3) and initializers of the basis and member (12.6.2) are called direct -initialization.

and

[C++11: 8.5/16]: semantics of initializers is as follows. [..]

  • If the initializer is an (not enclosed in parentheses) bit-init-list, the object or link is initialized with a list (8.5.4).
  • [..]
  • If initializer () , the object is initialized with a value.
  • [..]
  • If initialization is a direct initialization, or if it is a copy-initialization, where a cv-unqualified version of the source type of the same class as the derived class of the destination class is considered, the constructors are considered. The corresponding constructors are listed (13.3.1.3), and the best one is selected by overload resolution (13.3). The constructor selected in this way is called to initialize the object with an initializer expression or a list of expressions as argument (s). If the constructor is not used or if overload resolution is ambiguous, initialization is poorly formed.
  • [..]

So, you see, in this case (and several others), two are defined as direct initializations, but additional rules mean that different things can happen depending on whether you use () or {} and whether the initializer is empty.

Given the list initialization rules that I will not reproduce here, two initializers have essentially the same effect if T does not have a constructor that accepts std::initializer_list<> .

+4
source share

The general answer is no. Using a list with binding-initialization as an initializer will first try to allow the constructor that takes std::initializer_list . By way of illustration:

 #include <iostream> #include <vector> int main() { auto p = new std::vector<int>{1}; auto q = new std::vector<int>(1); std::cout << p->at(0) << '\n'; std::cout << q->at(0) << '\n'; } 

Note the semantics of list initialization (quoted from cppreference ):

  • All constructors that take std :: initializer_list as a single argument, or as the first argument, if the rest of the default arguments are checked and matched by overload resolution against a single argument of type std :: initializer_list
  • If the previous step does not give a match, all T constructors are involved in overload resolution by the set of arguments, which consists of elements of the bit-init list, with the restriction that only non-narrowing conversions are allowed. If this step creates an explicit constructor as the best match for copy-list-initialization, compilation fails (note, in simple copy-initialization, explicit constructors are not considered at all)
+4
source share

All Articles