Я неравнодушен к использованию списков инициализации членов с моими конструкторами ... но я давно забыл причины этого ...
Используете ли вы списки инициализации членов в ваших конструкторах? Если так, то почему? Если нет, то почему нет?
c++
oop
object-construction
paxos1977
источник
источник
Ответы:
Для учеников POD это не имеет значения, это просто вопрос стиля. Для членов класса, которые являются классами, тогда он избегает ненужного вызова конструктора по умолчанию. Рассматривать:
В этом случае конструктор для
B
вызовет конструктор по умолчанию дляA
, а затем инициализируетсяa.x
до 3. Лучшим способом было бы дляB
конструктора напрямую вызватьA
конструктор в списке инициализатора:Это будет вызывать только
A
«sA(int)
конструктор , а не его конструктор по умолчанию. В этом примере разница незначительна, но представьте, чтоA
конструктор по умолчанию сделал больше, например, выделил память или открыл файлы. Вы не хотели бы делать это без необходимости.Кроме того, если у класса нет конструктора по умолчанию или у вас есть
const
переменная-член, вы должны использовать список инициализаторов:источник
Помимо упомянутых выше причин производительности, если ваш класс хранит ссылки на объекты, переданные в качестве параметров конструктора, или у вашего класса есть переменные const, у вас нет выбора, кроме как использовать списки инициализатора.
источник
Одной из важных причин использования списка инициализатора конструктора, который здесь не упоминается, является инициализация базового класса.
Согласно порядку построения, базовый класс должен быть создан до дочернего класса. Без списка инициализатора конструктора это возможно, если в вашем базовом классе есть конструктор по умолчанию, который будет вызываться непосредственно перед входом в конструктор дочернего класса.
Но если ваш базовый класс имеет только параметризованный конструктор, то вы должны использовать список инициализатора конструктора, чтобы гарантировать, что ваш базовый класс инициализируется перед дочерним классом.
Инициализация подобъектов, которые имеют только параметризованные конструкторы
КПД
Используя список инициализатора конструктора, вы инициализируете элементы данных в точном состоянии, которое вам нужно в вашем коде, вместо того, чтобы сначала инициализировать их в их состояние по умолчанию, а затем изменить их состояние на то, которое вам нужно в вашем коде.
Если нестатические члены-данные const в вашем классе имеют конструкторы по умолчанию, и вы не используете список инициализатора конструктора, вы не сможете инициализировать их в заданное состояние, поскольку они будут инициализированы в состояние по умолчанию.
Члены ссылочных данных должны быть инициализированы, когда компилятор входит в конструктор, поскольку ссылки не могут быть просто объявлены и инициализированы позже. Это возможно только со списком инициализатора конструктора.
источник
Помимо проблем с производительностью, есть еще один очень важный момент, который я бы назвал обслуживаемостью и расширяемостью кода.
Если T является POD, и вы начинаете предпочитать список инициализации, то, если один раз T изменится на тип не POD, вам не нужно будет что-либо менять при инициализации, чтобы избежать ненужных вызовов конструктора, потому что он уже оптимизирован.
Если тип T имеет конструктор по умолчанию и один или несколько пользовательских конструкторов и один раз вы решили удалить или скрыть конструктор по умолчанию, то, если использовался список инициализации, вам не нужно обновлять код, если ваши пользовательские конструкторы, потому что они уже правильно реализованы.
То же самое с константными членами или ссылочными членами, скажем, изначально T определяется следующим образом:
Затем вы решаете квалифицировать a как const, если вы будете использовать список инициализации с самого начала, тогда это было изменение одной строкой, но, имея T, как указано выше, также необходимо выкопать определение конструктора для удаления присваивания:
Не секрет, что обслуживание намного проще и менее подвержено ошибкам, если код был написан не «обезьяной кода», а инженером, который принимает решения, основываясь на более глубоком рассмотрении того, что он делает.
источник
Перед запуском тела конструктора вызываются все конструкторы для его родительского класса, а затем для его полей. По умолчанию конструкторы без аргументов вызываются. Списки инициализации позволяют вам выбрать, какой конструктор вызывается и какие аргументы получает этот конструктор.
Если у вас есть ссылка или поле const, или если один из используемых классов не имеет конструктора по умолчанию, вы должны использовать список инициализации.
источник
Здесь компилятор выполняет следующие шаги для создания объекта типа MyClass
1. Конструктор типа сначала вызывается для «a».
2. Оператор присваивания «Type» вызывается внутри тела конструктора MyClass () для назначения
И, наконец, деструктор типа «Type» вызывается как «a», поскольку он выходит из области видимости.
Теперь рассмотрим тот же код с конструктором MyClass () со списком инициализаторов
С помощью списка инициализатора, следующие шаги выполняются компилятором:
источник
Просто добавьте некоторую дополнительную информацию, чтобы продемонстрировать, какую разницу может составить список инициализации члена . В leetcode 303 Range Sum Query - Immutable, https://leetcode.com/problems/range-sum-query-immutable/ , где вам нужно построить и инициализировать нулевой вектор с определенным размером. Вот две разные реализации и сравнение скорости.
Без списка инициализации члена , чтобы получить AC это стоило мне около 212 мс .
Теперь, используя список инициализации члена , время для получения AC составляет около 108 мс . На этом простом примере совершенно очевидно, что список инициализации членов гораздо эффективнее . Все измерения от времени выполнения от LC.
источник
Синтаксис:
Нужен список инициализации:
в приведенной выше программе, когда выполняется конструктор класса, создаются Sam_x и Sam_y . Затем в теле конструктора определяются эти переменные данных-членов.
Случаи использования:
В C переменные должны быть определены во время создания. Точно так же в C ++ мы должны инициализировать переменные Const и Reference во время создания объекта с помощью списка инициализации. если мы сделаем инициализацию после создания объекта (внутри тела конструктора), мы получим ошибку времени компиляции.
Объекты-члены класса Sample1 (base), которые не имеют конструктора по умолчанию
При создании объекта для производного класса, который будет внутренне вызывать конструктор производного класса и вызывать конструктор базового класса (по умолчанию). если базовый класс не имеет конструктора по умолчанию, пользователь получит ошибку времени компиляции. Чтобы избежать, мы должны иметь
Имя параметра конструктора класса и член Data класса одинаковы:
Как мы все знаем, локальная переменная имеет самый высокий приоритет, чем глобальная переменная, если обе переменные имеют одинаковое имя. В этом случае программа учитывает значение «i» {как левую, так и правую переменную. то есть: i = i} как локальная переменная в конструкторе Sample3 (), а переменная-член класса (i) получила переопределение. Чтобы избежать, мы должны использовать либо
источник
Как объясняется в C ++ Core Guidelines C.49: предпочитайте инициализацию присваиванию в конструкторах, это предотвращает ненужные вызовы конструкторов по умолчанию.
источник