int a = 5; int a(5); int a{5}; 4 answers
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
explicitand custom type conversions are considered. And with direct initialization, bothexplicit-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
- onethe 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.
- oneand why with
explicitfirst 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).explicitprohibits 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}; // Компилятор обязан запретить эту инициализацию
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