TTBOMK, есть три способа инициализации переменной в C ++.
int x = 0; // C-like initialization
int x (0); // Constructor initialization
int x {0}; // Uniform initialization
Единая инициализация была введена для C ++ 11 чтобы обеспечить более унифицированный синтаксис для инициализации различных типов переменных, что требовало другого синтаксиса в C ++ 03.
Каковы различия между C-подобным, конструктором и равномерной инициализацией? И я должен всегда использовать равномерную инициализацию?
Во-первых, я бы порекомендовал посмотреть на следующий разговор Херб Саттер, в котором он дает некоторые рекомендации по этому вопросу. Обсуждение инициализации фигурной скобки начинается в около 23:00.
Когда вы говорите о примитивных типах данных, все 3 дают одинаковый результат. Я лично предпочитаю придерживаться старого int x = 0
синтаксис, но все сводится к личным предпочтениям.
Для типов классов инициализация фигурных скобок и инициализация конструктора старой школы не являются полностью взаимозаменяемыми. Например:
vector<int> v (100); // Creates a 100-element vector
vector<int> v {100}; // Creates a 1-element vector, holding the value 100.
Это потому что std::vector
имеет конструктор, который явно определяет std::initializer_list
как единственный аргумент. Имейте в виду, что
auto var = {1, 2};
создает std::initializer_list
, с var
как его идентификатор.
Особенность списков инициализаторов заключается в том, что они обеспечивают согласованность, которая является долгожданным изменением по сравнению с тем, что было доступно ранее. Например, если бы вы инициализировали массив в C ++, вы бы использовали:
int arr[] = {1, 2, 3, 4};
Но, если вы хотите инициализировать vector<int>
с теми же элементами, вы должны были:
arr
а также arr + 4
С C ++ 11 вы можете просто использовать
vector<int> v = {1, 2, 3, 4}; // Same syntax. Nice! Note that the = is optional
Другой пример, в котором инициализация фигурной скобки полезна, заключается в том, что она предоставляет обходной путь для C ++. самый неприятный разбор. Из разговора предположим, что у нас есть два класса, origin
а также extents
, чьи экземпляры могут быть переданы для создания другого объекта типа rectangle
, Следующее утверждение:
rectangle w(origin(), extents());
не позволяет вам создать rectangle
использование объекта origin
а также extents
временные, потому что этот оператор анализируется как объявление функции. Тск тск. Так что обычно вам нужно сделать:
origin o;
extents e;
rectangle w(o, e);
С помощью инициализации скобок вы можете создавать их на лету, и
rectangle w {origin(), extents()};
будет работать как задумано, то есть передается конструктору, который перегружен origin
объект в качестве первого аргумента и extents
объект как второй.
Правило относится к объектам, используйте инициализацию скобок, если у вас нет причин не делать этого.
Каковы различия между c-like, конструктором и равномерной инициализацией?
Для примитивных типов, таких как int
нет практической разницы; так что давайте рассмотрим тип класса T
вместо.
Первый стиль эквивалентен
T x(T(0));
создание временного объекта из выражения инициализатора, а затем инициализация x
перемещая или копируя это. На практике перемещение или копирование будут исключены, так что результат будет таким же, как во втором стиле; единственное отличие состоит в том, что первое не удастся, если нет доступного конструктора копирования или перемещения.
Вторая напрямую инициализирует объект, используя конструктор, который принимает один аргумент, выдавая ошибку, если подходящего конструктора нет.
Третий зависит от того, какие конструкторы доступны.
std::initializer_list
он использует это;И я должен всегда использовать равномерную инициализацию?
Нет. Иногда вам нужна инициализация в стиле функции, чтобы различать initializer_list
конструктор и один принимает другие типы аргументов. Например:
std::vector<int> v1(10, 42); // 10 elements with value 42
std::vector<int> v2{10, 42}; // 2 elements with values 10 and 42
Вы также не должны называть это «равномерной инициализацией», поскольку она не является «однородной» в каком-либо значимом смысле. Официальный термин «инициализация скобки».