Списки инициализации в конструкторе

Я слышал, что преимущество использования списков инициализации в конструкторе заключается в том, что не будет лишних копий объектов типа класса. Но что это значит для следующего кода в конструкторе класса T? Если я прокомментирую назначение и использую списки инициализации, какая будет разница?

#include <iostream>
using std::cout;
using std::endl;
using std::ostream;

class X {

public:

    X(float f_x = 0, float f_y = 0):x(f_x), y(f_y) {}


    ~X() {}

    X(const X& obj):x(obj.x), y(obj.y) {}

    friend ostream& operator << (ostream &os, X &obj);

private:
    float x;
    float y;
};

ostream& operator << (ostream &os, X &obj)
{ os << "x = " << obj.x << " y = " << obj.y; return os;}

class T {

public:

    T(X &obj) : x(obj) { /* x = obj */ }

    ~T() { }

    friend ostream& operator << (ostream &os, T &obj);

private:

    X x;

};

ostream& operator << (ostream &os, T &obj)
{ os << obj.x; return os; }

int main()
{
    X temp_x(4.6f, 6.5f);

    T t(temp_x);

    cout << t << endl;

}

3 ответа

Решение

Это именно то, что вы уже сказали. Если вы не используете список инициализатора, то сначала будет вызван конструктор по умолчанию, а затем будет вызван оператор присваивания.

В вашем примере, это относительно мягко (думаю, компилятор может даже оптимизировать это). Но в других случаях просто невозможно избежать списка инициализаторов. Представь если X не было публичного оператора присваивания.

Если вы используете Назначение, то:
x будет построен по умолчанию первым &
затем назначается с obj,

Стоимость, Строительство по умолчанию + Назначение


Если вы используете список инициализаторов членов, то:
x будет построен и инициализирован с obj,

Стоимость только строительство

T(X &obj) : x(obj) {}

скопирует конструкцию x из obj, а

T(X &obj){ x = obj; }

создаст значение по умолчанию x только для того, чтобы затем заменить его значениями из obj.

Если вы намереваетесь создать объект-член, вы должны сделать это в списке инициализации.

Другие вопросы по тегам