# Перегруженные конструкторы стандартной библиотеки При проектировании стандартной библиотеки C++ было принято множество странных решений, из-за которых приходится страдать. И исправить их не представляется возможным из-за соображений обратной совместимости. Одним из таких странных решений являются перегрузки конструкторов с радикально различным поведением. Яркий [пример](https://gcc.godbolt.org/z/e3YnYx): ```C++ using namespace std::string_literals; std::string s1 { "Modern C++", 3 }; std::string s2 { "Modern C++"s, 3 }; std::cout << "S1: " << s1 << "\n"; std::cout << "S2: " << s2 << "\n"; ``` Этот код выведет ``` S1: Mod S2: ern C++ ``` Потому что у `std::basic_string` есть один конструктор, принимающий указатель и длину строки. А есть еще один конструктор, принимающий "что-то похожее на строку" и позицию, с которой надо из нее извлечь подстроку! На этом причуды не заканчиваются. ```C++ std::string s1 {'H', 3}; std::string s2 {3, 'H'}; std::string s3 (3, 'H'); std::cout << "S1: " << s1.size() << "\n"; std::cout << "S2: " << s2.size() << "\n"; std::cout << "S3: " << s3.size() << "\n"; ``` Этот [пример](https://gcc.godbolt.org/z/rrP67s) выведет ``` S1: 2 S2: 2 S3: 3 ``` Потому что у строки есть конструктор, принимающий число `n` и символ `c`, который нужно повторить `n` раз. А еще есть конструктор, принимающий список инициализации (`std::initializer_list`), состоящий из символов. И существование этого конструктора взаимодействует с неявным приведением типов! - `std::string s1 {'H', 3};` — строка "H\3" - `std::string s2 {3, 'H'};` — строка "\3H" - `std::string s3 (3, 'H');` — строка "HHH" Аналогичной проблемой страдает `std::vector` ```C++ std::vector v1 {3, 2}; // v1 == {3, 2} std::vector v2 (3, 2); // v2 == {2,2,2} ``` А еще у контейнеров есть конструктор, принимающий пару итераторов. И, казалось бы, с ними уж проблем-то не будет, но у нас есть указтели, которые также являются итераторами. А еще есть тип `bool`: ```C++ bool array[5] = {true, false, true, false, true}; std::vector vector {array, array + 5}; std::cout << vector.size() << "\n"; ``` [Будет выведено](https://gcc.godbolt.org/z/jobeh6) 2, а не 5. Потому что указатели неявно приводятся к `bool`! Собственно, эти прекрасные примеры показывают, почему "универсальная" иниациализация не универсальная. Чтобы не множить хаос в своих проектах, нужно быть осторожнее с объявлениями перегруженных конструкторов для своих типов. Лучше ввести статическую функцию, чем создавать перегруженные конструкторы, неожиданно взаимодействующие с неявным приведением типов и списками инициализации. ## Полезные ссылки 1. https://habr.com/ru/post/330402/