nullptr); // Компилируется
В официальной терминологии стандарта синтаксис, использованный для инициализации >r1
(со знаком равенства), соответствует инициализации копированием (сору initialization). Синтаксис же, использованный для инициализации >r2
(с круглыми скобками, хотя могут использоваться и фигурные), дает то, что называется прямой инициализацией (direct initialization). Инициализация копированием не может использовать конструкторы, объявленные как >explicit
, в то время как прямая инициализация — может. Вот почему строка с инициализацией >r1
не компилируется, в отличие от строки с инициализацией >r2
.
Но вернемся к >push_back
и >emplace_back
и в более общем случае — к функциям вставки и размещения. Функции размещения используют прямую инициализацию, т.e. могут пользоваться конструкторами, объявленными как >explicit
. Функции вставки применяют инициализацию копированием, а потому использовать такие конструкторы не могут.
>regexes.emplace_back(nullptr); // Компилируется. Прямая
> // инициализация разрешает использовать конструктор
> // explicit std::regex, получающий указатель
>regexes.push_back(nullptr); // Ошибка! Копирующая
> // инициализация такие конструкторы не использует
Урок, который следует извлечь из данного материала, состоит в том, что при использовании размещающих функций необходимо быть особенно осторожным и убедиться, что функциям передаются правильные аргументы, поскольку в ходе анализа кода будут рассмотрены даже конструкторы, объявленные как >explicit
.
Следует запомнить
• В принципе, функции размещения должны иногда быть более эффективными, чем соответствующие функции вставки, и не должны быть менее эффективными.
• На практике они чаще всего более быстрые, когда (1) добавляемое значение конструируется в контейнере, а не присваивается; (2) типы передаваемых аргументов отличаются от типа, хранящегося в контейнере; и (3) контейнер не отвергает дубликаты уже содержащихся в нем значений.
• Функции размещения могут выполнять преобразования типов, отвергаемые функциями вставки.