3
#include <iostream>

using namespace std;

class C{
    public: int a;
    public: C (int i){a = i ; }

};
int main()
{
    C c(3); // C c{3};
    cout<<c.a;
    return 0;
}

What is the difference between C c(3); and C c{3};? They seem to work the same as invoking the constructor.

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182

2 Answers2

4

There are two differences:

  1. The brace-initialization syntax (assuming the list is nonempty) can call an std::initializer_list<T> constructor, and will always do so if possible. The parenthesis syntax will not call an std::initializer_list<T> constructor.

  2. The brace-initialization syntax prohibits narrowing conversions.

In your example there is no difference, but:

  1. If C had a constructor taking std::initializer_list<int> then C{3} would call that constructor while C(3) would call the one that takes int.

  2. C{3.14} will not compile since the conversion is narrowing, but C(3.14) will.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • Thanks. May i ask which style of `C c(3)` and `C c{3}` is more popular in other languages with OO? Is it correct that Java and C# don't have either? –  Nov 03 '17 at 01:55
  • C# and Java have constructors that are almost the same as `C(int i)`, only with the caveat that they do check for the type being passed in. `new C(3.14)` would fail to compile. There is no support for the `{}` syntax, though. In C#, `new C { a = 3 }` is an object initializer, and you must assign member variables within the `{}`. – moswald Nov 03 '17 at 02:05
  • 3
    Your first Statement 1 is untrue in general: aggregate initialization is highest priority; then value-initialization for an empty list. Then there is the case where `C` is itself a `std::initializer_list`. And only then , constructors are considered at which point overload resolution has a chance to match a constructor of `C` which accepts `std::initializer_list`. As of C++14 anyway -- the order of things in the list-initialization spec seems to jump around with every new standard draft – M.M Nov 03 '17 at 02:06
  • 1
    @M.M Good point about the empty list, I'll update my answer to reflect that. I don't think aggregate initialization conflicts with what I wrote, because a class can't both be an aggregate and have a `std::initializer_list` constructor. – Brian Bi Nov 03 '17 at 04:24
  • Good answer. It also prevents this case https://en.wikipedia.org/wiki/Most_vexing_parse – Ben Nov 03 '17 at 05:53
  • @Ben: It seems that using `{}` is encouraged by the experts. I've [asked](https://stackoverflow.com/questions/46403621/why-uniform-initialization-initialization-with-braces-is-recommended) why, but unfortunately, no strong answer have been given yet. – geza Nov 03 '17 at 11:11
  • @Ben honestly I don't think it matters too much, but some people like the safety of `{}` because it avoids accidental narrowing conversions – Brian Bi Nov 03 '17 at 21:22
1

The effect is same for this case.

C c(3); is direct intialization,

the constructors of T are examined and the best match is selected by overload resolution. The constructor is then called to initialize the object.

C c{3}; is direct-list-initialization (since C++11),

If the previous stage does not produce a match, all constructors of T participate in overload resolution against the set of arguments that consists of the elements of the braced-init-list, with the restriction that only non-narrowing conversions are allowed.

So for both cases C::C(int) is used for initializing the object.


Depending on the behavior of C, the other potential differences between C c(3); and C c{3}; include:

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • Thanks. May i ask which style of `C c(3)` and `C c{3}` is more popular in other languages with OO? Is it correct that Java and C# don't have either? –  Nov 03 '17 at 01:55
  • @Ben I'm not sure, I guess it's `C c(3)`. List initialization is introduced from C++11, in C++ it's considered as *modern style*. :) – songyuanyao Nov 03 '17 at 01:59