int a = 5; int a(5); int a{5}; 
  • one
    @arukasa, I confess right away that I don’t like crosses and therefore I don’t know well. My guess is the third initialization variant ( a{...} ), which semantically coincides with the second one, however, is visually less terrible than the second (which surprisingly resembles the recording of either a function call, or its prototype with errors). Apparently, the awareness of this fact was still visited by a number of language developers. (since option (2) still needs to be left, then an alternative explanation with simplification of the parser in compilers, etc. disappears ... (Björn had to think about this much earlier)) - avp
  • 2
    yes, actually no. - pavel
  • 7
    but if instead of int there would be a big tricky class, then the difference may be. Already, even for std :: vector, the first option will not compile, and the other two will give completely different results. - KoVadim
  • one
    @ user235562 In this particular example, the difference is in the programming style. The first declaration is familiar and understandable to everyone, not even knowing C ++. The other two declarations for fundamental types are simply a bad programming style, since they only confuse the reader of the code, and he, like you, only has questions as to why this is done. By the way, you still forgot about the declaration int x = {5}; - Vlad from Moscow
  • @VladfromMoscow as far as I know, many people on the contrary recommend using curly brackets for a unified style - user235562

4 answers 4

The second and third options are no different - this is direct initialization . The first option is copy initialization .

The difference is described in the same place (my translation):

Direct initialization is more lenient than copy initialization. With copying initialization, only constructors that are not marked with the keyword explicit and custom type conversions are considered. And with direct initialization, both explicit -constructors and type-conversion sequences are also considered.

For primitive built-in types there is no difference. But for classes the difference appears. For example, if your Complex class has a explicit constructor from double , then you cannot initialize Complex with the first syntax, but with the second and third, completely.

Yes, I also do not understand why a normal developer should keep these subtleties in his head . This is a feature of the C ++ language, apparently.

  • @VladD unless the code int a {5}; not a mistake? - perfect
  • one
    @perfect, in C ++ 11 and beyond - this is possible. For example, g ++ 4.8.2 understands this entry for the values ​​-std = c ++ 11, gnu ++ 11, c ++ 1y and gnu ++ 1y - avp
  • one
    the older the language, the more confusing it becomes - perfect
  • > the older the language, the more confusing it becomes especially well illustrated by human languages, in which there are more exceptions than rules - DreamChild
  • @DreamChild yes certainly seems to be true - perfect

Consider the difference briefly. Suppose we have a certain class, and we write explicitly

 test x = 5; 

for this to work, the class must have a view constructor

 test(int x) {} 

if you make an explicit constructor, it will not work anymore.

 explicit test(int x) {} 

line

 test x(5); 

wants exactly the same constructor, but will work with both constructors. And exactly as expected.

line

 test{5}; 

this is a newfangled invention (c ++ 11). He wants a special designer

 test(std::initializer_list<int> x) {} 

But this designer also understands

 test x{1,2,3,4}; 

which is sometimes very convenient.

There is a similar difference in the case of std :: vector. construction std::vector<int> x(5); will create a vector of 5 elements with zeros (default value for int), and std::vector<int> x{5}; will create a vector on one element with a value of 5.

Why do many people recommend the method with brackets? apparently just for this reason. They are tired of the fact that the vector creates just a few elements (which some consider unobvious, since int x(5) does exactly initialization) and have developed the habit of writing in curly braces. Naturally it is promoted. This is exactly the same as the well-known Yoda condition - modern compilers have long learned to beat on fingers for assignment, but programmers continue to write in the old way.

How to write in real code? write as required code-style. But for simple types, I still wrote simply through assignment.

  • one
    and why with explicit first option does not work? he also prohibits casting, is it there? - user235562
  • of course have. cast by int to test. - KoVadim
  • @ user235562, any constructor with one parameter is treated as a type conversion constructor (similar to operator T() , but on the other side of the assignment sign). explicit prohibits a similar interpretation - ߊߚߤߘ
  • @Arhad cast int to test and not vice versa? - user235562
  • @ user235562, yes. The constructor belongs to the type test , respectively, an instance of this type is created. - ߊߚߤߘ

In the first case - everything is transparent - this is initialization with the help of a literal (most likely I forgot and this is called differently by “science”, but not the essence). Such initialization is applicable only to basic types (the same int , double , etc.), since only for them there are literals. This method is convenient for its short syntax

In the second case, a constructor is used (yes, basic tippers also have constructors) There is no difference in principle (correct if you are mistaken, but this wonderful service shows that in both cases the same code is generated). There are no advantages over the first type, but it looks longer and slightly less intuitive (in the case of basic types), and therefore the first option is often used.

The third option is to use the initialization list, the capabilities of which have been significantly expanded in C ++ 11. In this case, there is a difference - if using the first two methods, instead of int, you slip a double , for example, the compiler will not say anything to you, but will simply implicitly convert it to an int . However, using the third option, you will see an error. For example:

 int a1 = 5.5; // ошибки нет int a2(5.5); // ошибки нет int a3{ 5.5 }; // ошибка компиляции 
  • int a {5.5}; - no error. Even the service that you got rid of compiles everything well, by the way, thanks for it. But still I want some more general view, because there was some reason to add {} - arukasa
  • as for the third option, then, as I wrote above, it was added to support lists of initialization (handy thing, but in the case of more complex than basic types). On the occasion of a compilation error - here, apparently, there is a dependency on the compiler. I checked in Visual C ++ and there, when I try to stuff a double, an error falls out. However, gcc does not produce errors, although, as far as I know, such behavior is inherent in the standard, and gcc standard C ++ 11 implements entirely (or almost entirely) - DreamChild

I also add that curly brackets prohibit the use of a narrowing transformation , i.e. if the value may not fit in the type.

For example,

 int x = 5; char c(x); // Компилятор может предупредить о сужающем преобразовании char s{x}; // Компилятор обязан запретить эту инициализацию