Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the difference between `Object obj(args...)` and `Object obj{args...}`?

The draft book Effective C++11 by Scott Meyers states:

Distinguish () and {} when creating objects

What's the difference between Object obj(args...) and Object obj{args...}? and why Scott says so.

Update:

The question How to use C++11 uniform initialization syntax? asks for HOW, and this question asks for WHY.

Update2:

I find the following link is helpful and completely answers this question:

https://softwareengineering.stackexchange.com/questions/133688/is-c11-uniform-initialization-a-replacement-for-the-old-style-syntax

like image 512
xmllmx Avatar asked Jul 13 '14 06:07

xmllmx


2 Answers

What's the difference between Object obj(args...) and Object obj{args...}?

The first is direct-initialization while the second is direct-list-initialization. This is mentioned in two different sections:

§8.5/16 [dcl.init]

The initialization that occurs in the forms

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

as well as in new expressions (5.3.4), static_cast expressions (5.2.9), functional notation type conversions (5.2.3), and base and member initializers (12.6.2) is called direct-initialization.

and §8.5.4/1 [dcl.init.list]

List-initialization is initialization of an object or reference from a braced-init-list. Such an initializer is called an initializer list, and the comma-separated initializer-clauses of the list are called the elements of the initializer list. An initializer list may be empty. List-initialization can occur in direct-initialization or copy-initialization contexts; list-initialization in a direct-initialization context is called direct-list-initialization and list-initialization in a copy-initialization context is called copy-list-initialization.


There are a few differences between the two:

  • If the type being constructed has a constructor that takes an initializer_list argument, direct-list-initialization will always favor that constructor. Other constructors will only be considered if the initializer_list constructor is not viable. §13.3.1.7/1 [over.match.list]

  • direct-list-initialization does not allow narrowing conversions within the argument list. §8.5.4/3 [dcl.init.list]

  • If the type being initialized is an aggregate, direct-list-initialization will perform aggregate initialization. §8.5.4/3 [dcl.init.list]

  • The order of evaluation of the elements of a braced-init-list is from left to right. §8.5.4/4 [dcl.init.list]

  • You can avoid the most vexing parse by using direct-list-initialization

 

  struct foo{};
  struct bar 
  {    
    bar(foo const&) {}
  };

  bar b1(foo()); // most vexing parse
  bar b2(foo{}); // all 3 of the following construct objects of type bar
  bar b3{foo()};
  bar b4{foo{}};
like image 104
Praetorian Avatar answered Sep 28 '22 12:09

Praetorian


The behavior of Object obj(args...) and Object{args...} depends on the constructors defined in Object.

Take the following example:

#include <iostream>
#include <initializer_list>

struct A
{
   A(int a, int b) {std::cout << "Came to A::A()\n";}
};

struct B
{
   B(int a, int b) {std::cout << "Came to B::B(int, int)\n";}
   B(std::initializer_list<int> in) {std::cout << "Came to B::B(std::initializer_list<int>)\n";}
};

int main()
{
   A a1(10, 20); // Resolves to A(int, int)
   A a2{10, 20}; // Resolves to A(int, int)
   A a3{30};     // Does not resolve to anything. It's a compiler error.

   B b1(10, 20); // Resolves to B(int, int)
   B b2{10, 20}; // Resolves to B(std::initializer_list<int> )
   B b3{30};     // Resolves to B(std::initializer_list<int> )

}
like image 24
R Sahu Avatar answered Sep 28 '22 10:09

R Sahu