Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does data get assigned without an extra copy being created, in an initialization list?

Parashift explains initialization lists well, but does not explain why an extra copy of a variable is created before assignment in the ctor body, but no extra copy is created when assigned through an initialization list.
I've even come across advice of using ++i instead of i++ because the former avoids creation of a temporary i before assignment. Is it the same for POD's assigned in a ctor body? A temp variable gets created before the assignment happens?

To put it another way, why does the compiler need to create an extra copy of a variable? Why can't it just assign the variable directly?
Why?

like image 974
Nav Avatar asked Jul 13 '11 05:07

Nav


People also ask

What is assignment and copy initialization?

Direct Initialization or Assignment Operator (Syntax) This assigns the value of one object to another object both of which are already exists. Copy initialization is used when a new object is created with some existing object. This is used when we want to assign existing object to new object.

How does initialization work?

Initialization is the process of locating and using the defined values for variable data that is used by a computer program. For example, an operating system or application program is installed with default or user-specified values that determine certain aspects of how the system or program is to function.

What is initializer list used for?

Initializer List is used in initializing the data members of a class. The list of members to be initialized is indicated with constructor as a comma-separated list followed by a colon. Following is an example that uses the initializer list to initialize x and y of Point class.

What are the advantages of initializer list?

The most common benefit of doing this is improved performance. If the expression whatever is the same type as member variable x_, the result of the whatever expression is constructed directly inside x_ — the compiler does not make a separate copy of the object.


3 Answers

Consider the following:

struct C { 
    C() { /* construct the object */ }
};

struct X {
    C member;

    X() { member = C(); }
};

The X() constructor is the same as if you had said:

X() : member() { member = C(); }

First, the C constructor is called to construct the member data member. Then the body of X is executed, a second, temporary C object is created and assigned to member, then the temporary is destroyed.


Note that this is only the case for types that are initialized automatically. If member was of type int or of a POD class type (as examples), it would be uninitalized when the body of the X constructor is entered.

For such types it doesn't really matter from a performance standpoint whether you initialize the data member in the initialization list or assign to the data member in the body of the constructor; the difference is entirely stylistic. Where possible, the initialization list should still be preferred for the sake of consistency.

like image 93
James McNellis Avatar answered Nov 08 '22 05:11

James McNellis


To address your first question specifically regarding the copy (without touching on "++i" vs "i++"):

The constructor is a function, and it has parameters. These parameters are copies of the variables passed as parameters (unless passing by reference is used). You can now manipulate this copy or do anything else with it. Then when you assign, you take this copy of the parameter (possibility manipulated) and assign it to the member variable. When you use an initialization list, the compiler can optimize the assignment immediately without this copy, as you will not be using it for anything but the initialization (and cannot modify it before assigning it to the member variable).

like image 41
Michael Petrov Avatar answered Nov 08 '22 05:11

Michael Petrov


why an extra copy of a variable is created before assignment in the ctor body, but no extra copy is created when assigned through an initialization list.

Because assignment follows initialization. In other words, assignment is optional, but initialization is mandatory. You may not notice much difference for PODs. But the same holds true for user defined data types.

advice of using ++i instead of i++

Again for PODs it doesn't matter much. But for user defined classes, i++ does create a temporary copy. So it's better to use ++i.

struct A {
  A operator ++ (int)  // example of i++
  {
    A temp = *this;
    this->value ++;
    return temp;    // makes 2 copies "temp" and return value
  }
  A& operator ++ ()  // example of ++i
  {
    this->value ++;
    return *this;  // no copy
  }
};
like image 32
iammilind Avatar answered Nov 08 '22 06:11

iammilind