Class construction with initial values

I am new to C ++ and the whole idea of ​​classes is that I am still reading a book to try and learn. The book I'm reading says that when I create a class, I can assign default values ​​by doing the following:

class foo { public: foo(char c, int i); private: char exampleChar; int exampleInt; }; foo::foo(char c, int i): exampleChar(c), exampleInt(i) {} 

This code (for me) looks very dirty and does not comply with the rules that I'm used to in other languages. My question is, what is the difference between doing the above and this (below, which I personally consider a lot cleaner)?

 foo::foo(char c, int i) { exampleChar = c; exampleInt = i; } 

I think about the elements: are there any issues with performance / efficiency if they are made on a large scale, or is it exactly the same?

+6
source share
8 answers

The first way, by doing : exampleChar(c), exampleInt(i) , is called a list of initializers.

If you do this in the second way, two variables are built by default by default 1 then you assign them a value. (When the actual constructor element is introduced, everything that was not initialized by the initializer list is built by default.) This is a waste of time because you are simply rewriting the values ​​anyway. For small types, such as int or char , this does not really matter, but when these member variables are large types that require many loops to build, you definitely want to use a list of initializers.

The second method will not lose time by indicating to it the default value and then overwriting it - it will set its values ​​directly to the value that you give it (or call the right constructor if the element is an object).

You can understand what we mean:

 class MyClass { public: int _i; // our data // default constructor MyClass() : _i(0) { cout << "default constructor"; } // constructor that takes an int MyClass(int i) : _i(i) { cout << "int constructor"; } // assignment operator void operator=(int i) { _i = i; cout << "assignment operator"; } }; class OtherClass { public: MyClass c; OtherClass() { c = 54; } }; OtherClass oc; 

You will see that

 default constructor assignment operator 

. These are two function calls that can be expensive for other classes.

If you change the constructor of OtherClass to

 OtherClass() : c(54) { } 

You will see that

 int constructor 

. Just one call compared to two. This is the most effective way.

Initializer lists are also required when you

  • have types that do not have a default constructor. You must call the correct constructor in the initializer list.

  • has a const member that you want to give some value (instead of just having a default value by default

  • have a reference element. You should use initialization lists on them.

tl; dr: do it because it is at least as fast, but not slower than the other, and sometimes much faster.

1 For built-in types such as int and char , they are not actually constructed; they simply have the value of any memory they used to be with.

+10
source

The difference is that the compiler will always initialize all members (in the order of declaration) to the first user-defined constructor statement. In the case of char and int , which are both primitive types, “initialization” actually means “no initialization” here. However, if you have a member with a constructor that does some actual work, that constructor will be called upfront - if you do

 foo::foo() { myComplexMember = MyComplexClass(42); } 

the compiler already called the default constructor MyComplexClass before your code received the call, which is a waste of resources (and a compiler error if ctor is not available by default).

Using the initialization list, you can configure the default initialization and avoid anything in common. Obviously, this is the way to go.

+5
source

There are things you can do so that you cannot do otherwise.

  • If one of the members does not have a default constructor. This is the only way to initiate a participant during construction. (the same applies to the base class)

  • You can assign a value to the const member.

  • You can guarantee a specific state for the class before running the constructor function.

  • If the item is a link, it must be initialized in the initialization list. Since links are immutable and can only be initialized once at the beginning (e.g. const)

+5
source

Well, this is a typical FAQ question: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.6

In your case using char and int there are no differences.

General rule: use the initialization list whenever possible, there are very few cases where you may prefer an assignment, for example, to improve readability:

 MyClass::MyClass { a = b = c = d = e = f = 0; } 

better than

 class MyClass::MyClass : a(0), b(0), c(0), d(0), e(0), f(0) { } 
+1
source

If members had non-trivial constructors, the default constructors will be called in the code below, then the assignments will be completed, and in the code above they will be initialized only once. So yes, there may be a performance issue.

There is also a practical problem: if they are constants, references, or do not have default constructors, you cannot use the version below.

+1
source

There is a subtle but important difference between the two. What you have at the top is called a member initialization list. When an object is created, the members in this list are initialized by what you put in parentheses.

When you perform an assignment in the constructor body, the values ​​are first initialized and then assigned. I will give a short example below.

Example 1: Member Initialization

 class foo { public: foo(char c, int i); private: char exampleChar; int exampleInt; Bar exampleBar; }; foo::foo(char c, int i): exampleChar(c), exampleInt(i), exampleBar() //Here, a bar is being default constructed { } 

Example 2: Designator Assignment

 class foo { public: foo(char c, int i, Bar b); private: char exampleChar; int exampleInt; Bar exampleBar; }; foo::foo(char c, int i, Bar b): //exampleChar(c), //exampleInt(i), //exampleBar() { exampleChar = c; exampleInt = i; exampleBar = someOtherBar; //Here, a bar is being assigned } 

Here it becomes interesting. Note that exampleBar is assigned. Behind the scenes, a Bar is actually first configured by default, although you did not specify this. In addition, if your Bar more complex than a simple structure, you need to implement an assignment operator so that you can initialize it this way. In addition, to initialize a Bar from another Bar from the member initialization list, you must implement the copy constructor!

Example 3: Copy the constructor used in the init element

 class foo { public: foo(char c, int i, Bar b); private: char exampleChar; int exampleInt; Bar exampleBar; }; foo::foo(char c, int i, Bar b): //exampleChar(c), //exampleInt(i), exampleBar(b) //Here, a bar is being constructed using the copy constructor of Bar { exampleChar = c; exampleInt = i; } 
+1
source

I would be used to using initialization lists. They will not suffer from problems when someone changes char to some object, where the default constructor is called first, and also for constant correctness for const values!

0
source
 foo::foo(char c, int i):exampleChar(c),exampleInt(i){} 

This construct is called the Member initializer list in C ++.

It initializes your exampleChar member to c and exampleInt to i .


What is the difference between initialization and assignment inside a constructor? & Amp;
What is the advantage?

There is a difference between Initializing a member using a list of initializers and assigning it a value inside the constructor body.

When you initialize fields through a list of initializers, constructors will be called once.

If you use assignment, then the fields will be initialized by the default constructors first, and then reassigned (via the assignment operator) with the actual values.

As you can see, the latter has additional overhead for creating and assigning, which can be significant for user-defined classes.

There is no practical overhead for the integer data type (for which you use it) or members of the POD class.

0
source

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


All Articles