Преимущества списков инициализации
Из того, что я знаю о преимуществах использования списка инициализации, является то, что они обеспечивают эффективность при инициализации членов класса, которые не являются встроенными. Например,
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
объект) и что работа оптимизирована полностью в оптимизированной сборке. но все еще считается хорошей формой использовать списки инициализаторов всякий раз, когда это возможно.
Ниже приведены сценарии использования списка инициализаторов:
- Для инициализации нестатических элементов данных const.
- Для инициализации референтных членов.
- Для инициализации объектов-членов, которые не имеют конструктора по умолчанию.
- Для инициализации членов базового класса.
- Когда имя параметра конструктора совпадает с элементом данных.
- По причинам производительности.
Мы также можем выполнить делегирование конструктора через список инициализации.