Преимущества списков инициализации

Из того, что я знаю о преимуществах использования списка инициализации, является то, что они обеспечивают эффективность при инициализации членов класса, которые не являются встроенными. Например,

Fred::Fred() : x_(whatever) { }

предпочтительнее,

Fred::Fred() { x_ = whatever; }

если х является объектом пользовательского класса. Помимо этого, этот стиль используется даже со встроенными типами для согласованности.

Наиболее распространенным преимуществом этого является повышение производительности. Если выражение любого типа того же типа, что и переменная-член x_, результат выражения any создается непосредственно внутри x_ - компилятор не создает отдельную копию объекта.

С другим стилем выражение, которое вызывает создание отдельного временного объекта, и этот временный объект передается в оператор присваивания объекта x_. Затем этот временный объект разрушается на; Это неэффективно.

Вопрос
Есть ли какой-либо выигрыш в эффективности в следующем примере с использованием списка инициализации. Я думаю, что нет никакой выгоды. Первая версия вызывает конструктор копирования строки, а другая вызывает оператор присваивания строки (временные файлы не созданы). Это что правильно?

class MyClass
{
public:
    MyClass(string n):name(n) { }
private:
    string name;
};

class MyClass
{
public:
    MyClass(string n)
    {
        name=n;
    }
private:
    string name;
};

6 ответов

Решение

Вторая версия вызывает строковый ctor по умолчанию, а затем оператор копирования-присваивания строки - определенно могут быть (незначительные) потери эффективности по сравнению с первой, которая напрямую вызывает copy-ctor c (например, в зависимости от реализации строки, может быть бесполезное выделение-затем-релиз какой-то крошечной структуры). Почему бы просто не всегда использовать правильный путь?-)

Я думаю, что единственный способ инициализации константных членов данных находится в списке инициализации

Например. в шапке:

class C
{
    C();
private:
    const int x;
    int y;
}

И в файле cpp:

C::C() :
    x( 10 ),
    y( 10 )
{
    x = 20; // fails
    y = 20;
}

Это отличный способ инициализировать участников, которые:

  • являются постоянными
  • не имеет конструктора по умолчанию (это приватно)

Помните, что есть разница между конструктором копирования и оператором присваивания:

  • копия ctor создает новый объект, используя какой-то другой экземпляр в качестве места для получения информации об инициализации.
  • оператор присваивания изменяет уже существующий объект, который уже был полностью построен (даже если это только с помощью конструктора по умолчанию)

Итак, во втором примере уже была проделана определенная работа по созданию name к тому времени

 name=n;

достигнуто

Однако вполне возможно (особенно в этом простом примере), что проделанная работа исчезающе мала (возможно, просто обнуляя некоторые элементы данных в string объект) и что работа оптимизирована полностью в оптимизированной сборке. но все еще считается хорошей формой использовать списки инициализаторов всякий раз, когда это возможно.

Ниже приведены сценарии использования списка инициализаторов:

  1. Для инициализации нестатических элементов данных const.
  2. Для инициализации референтных членов.
  3. Для инициализации объектов-членов, которые не имеют конструктора по умолчанию.
  4. Для инициализации членов базового класса.
  5. Когда имя параметра конструктора совпадает с элементом данных.
  6. По причинам производительности.

Мы также можем выполнить делегирование конструктора через список инициализации.

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