Универсальная инициализация и непростые пути инициализации векторов
Живете вы себе такой спокойно, хотите по фану создать массив на 10 элементов. И пишите:
std::vector<int> vector{10};
Запустив свой код, вы нихера не понимаете, че происходит. Поведение совершенно не такое, какое ожидалось при запуске. Проверяете все части программы, все в порядке. И доходите до того, что у вас в векторе не 10 элементов, а всего 1. WTF?! Щас разберемся.
Универсальная инициализация, представленная в C++11, позволяет нам инициализировать объекты, используя один набор фигурных скобок {}. Это безопасный и удобный способ инициализации различных типов. Не буду перечислять причин удобства, можете поверить на слово. Однако, когда дело доходит до инициализации векторов, возникает несколько препятствий.
На самом деле, не только векторов. А всех классов с конструкторами от std::initializer_list. Дело в том, что эта перегрузка затемняет все другие конструкторы класса. То есть, если вы определили такой конструктор и вы используете универсальную инициализацию, то компилятор всегда будет предполагать, что вы хотите вызвать именно конструктор от std::initializer_list. Даже если другие перегрузки будут иметь намного больший смысл. В основном эта проблема касается именно числовых типов. Но после С++17, когда мы можем опускать шаблонный параметр вектора, проблема заиграла новыми красками.
Что же с этим делать?
Универсального способа, конечно, нет. В разных командах существуют разные гайдлайны, как решать проблему. Приведу несколько общих правил, которые помогут не попадаться в ловушку:
Если вы намеренно используете список инициализации в качестве параметра конструктора, то можно явно его создавать, используя explicit конструктор. Типа того:
std::vector<int> myVector{std::initializer_list<int>{1, 2, 3}};. Это никогда не создаст семантическую путаницу.
Для инициализации объектов классов с помощью обычных аргументов используйте круглые скобки. Это предотвратит интерпретацию компилятором параметров как списка инициализации и поспособствует вызову нужных конструкторов.
Проектируйте свои классы, чтобы этой путаницы не происходило. Мы не можем повлиять на код стандартной библиотеки. Но можем в своих проектах придерживаться порядка и однозначности.
Stay well-designed. Stay cool.
#cpp11 #design #STL