What are the differences between the list of member initializers and the default element initializer for a non-static data element?

I would like to understand what are the differences in using one form and not another (if any).

Code 1 (init directly by variables):

#include <iostream> using namespace std; class Test { public: Test() { cout<< count; } ~Test(); private: int count=10; }; int main() { Test* test = new Test(); } 

Code 2 (init with an initialization list in the constructor):

 #include <iostream> using namespace std; class Test { public: Test() : count(10) { cout<< count; } ~Test(); private: int count; }; int main() { Test* test = new Test(); } 

Is there a difference in semantics or just syntactic?

+5
source share
5 answers

Member Initialization

In both cases, we are talking about the initialization of the participant . Keep in mind that members are initialized in the sequence in which they are declared in the class.

Code 2: Member Initializer List

In the second version:

 Test() : count(10) { 

: count(10) is the constructor initializer ( ctor-initializer ) and count(10) is the element initiator as part of a list of member initializers. I like to think of it as a β€œreal” or primary way of initializing, but does not define the sequence of initialization.

Code 1: default element initializer

In the first version:

 private: int count=10; 

count has a default initialization member. This is a backup option. It will be used as a member initializer, if not in the constructor, but the sequence of elements for initialization is defined in the class.

From section 12.6.2 Initialization of the bases and members, clause 10 of the standard:

If a given non-static data member has both a sliding or peer-initializer and a mem-initializer, the initialization specified by the mem-initializer and non-static data the member-member-bit-or-equal-initializer is ignored. [Example: given

 struct A { int i = / some integer expression with side effects / ; A(int arg) : i(arg) { } // ... }; 

the constructor A (int) simply initializes me with the arg value, and side effects in the parenthesized state or -regulator will not take place. -end example]

Something else to keep in mind would be that if you enter a non-static data initializer, then the structure will no longer be considered an aggregate in C ++ 11, but this has been updated for C ++ 14 .


Differences

what are the differences in using one form and not another (if any).

  • Difference is the priority given to two options. The initial constructor initializer takes precedence. In both cases, we get the element initializer through different paths.
  • It is better to use the default element initializer, because
    • then the compiler can use this information to create a list of constructor initializers for you, and it can optimize.
    • You can see all the defaults in one place and in sequence.
    • This reduces duplication. Then you can only place exceptions on the initializer list specified manually.
+2
source

In C ++ Fundamentals (see Note 1 below), the C.48 Guide recommends the first approach (class initializers). argumentation:

Indicates that the same value is expected in all constructors. Avoids repetition. Avoids maintenance issues. This leads to the shortest and most efficient code.

In fact, if your constructor does nothing but initialize member variables, as in your question, Guideline C.45 is even harder, saying of course, use initializers in the class. This explains that

Using class member initializers allows the compiler to generate this function for you. The function generated by the compiler may be more efficient.

I am not going to argue with Straustup, Sutter, and several hundred of their friends and colleagues, even if I did not write a compiler, so I can not prove it works more efficiently. Use initializers in the class, wherever you are.

  • If you are not familiar with the recommendations, follow the links to see sample code and additional explanations.
+5
source

The difference I can think of is that the list of member initializers is before the default element initializer .

Through the initializer of the default element, which is simply a bracket or equal to the initializer included in the participant's declaration, which is used if the element is omitted from the list of member initializers.

If the member has a default member initializer, and also appears in the member initialization member in the constructor, the default member initializer is ignored.

For instance:

 class Test { public: Test() {} // count will be 10 since it omitted in the member initializer list Test(int c) : count(c) {} // count value will be c, the default member initializer is ignored. private: int count = 10; }; 
+4
source

There is no difference in the code. The difference would have arisen if you had more than one constructor overload and more than one account had 10. You would have less spelling with the first version.

 class Test { public: Test() = default; Test(int b) : b(b) {} // a = 1, c = 3 ~Test(); private: int a = 1; int b = 2; int c = 3; }; 

Unlike the second version, where the above code will look like this:

 class Test { public: Test() : a(1), b(2), c(3) {} Test(int b) : a(1), b(b), c(3) {} ~Test(); private: int a; int b; int c; }; 

The difference increases with a large number of member variables.

+2
source

When you initialize next to a member declaration, this is only valid in C ++ 11, so if you are in C ++ 98/03, you cannot do this.

If the value never changes, you can choose constexpr static instead, and then the compiler will need to not use additional storage for the value (until you define it) and instant use constant distribution wherever the value is used.

One of the drawbacks of using the by-declaration syntax is that it must be in the header, which will recompile all translation units that include the header every time you want to change its value. If this takes a long time, this may be unacceptable.

Another difference is that using a member initialization list allows you to change the value for each constructor, while using the by-declaration version allows you to specify only one value for all constructors (although you can overwrite this value ... but I "Personally avoid this as it can become quite confusing!).


As an aside, there is no need to use new here to create an instance of Test . This is a common mistake when people come to a language from other languages, and I wanted to inform you about it. Of course, you do not need to use it outside of your example.

+1
source

Source: https://habr.com/ru/post/1247041/


All Articles