Для чего нужен explicit конструктор в C++?

«Для чего нужен explicit конструктор в C++?» — вопрос из категории C++ Core, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Ключевое слово explicit применяется к конструкторам с одним параметром (или с несколькими, где все параметры, кроме первого, имеют значения по умолчанию) для запрета неявных преобразований типов. Это предотвращает неожиданное и потенциально ошибочное создание объектов компилятором.

Проблема без explicit:

class StringWrapper {
public:
    StringWrapper(const char* str) { /* ... */ } // Неявное преобразование разрешено
};

void processString(const StringWrapper& sw) { /* ... */ }

int main() {
    processString("hello"); // Компилятор неявно создаст временный объект StringWrapper.
    // Это может быть неочевидно и привести к трудноуловимым ошибкам.
}

Решение с explicit:

class StringWrapper {
public:
    explicit StringWrapper(const char* str) { /* ... */ } // Явный конструктор
};

void processString(const StringWrapper& sw) { /* ... */ }

int main() {
    // processString("hello"); // Ошибка компиляции: нельзя преобразовать 'const char*' в 'StringWrapper'
    processString(StringWrapper("hello")); // OK: явное создание объекта
    StringWrapper sw = "world"; // Ошибка: copy-initialization не сработает
    StringWrapper sw2("world"); // OK: direct-initialization
}

Когда использовать: Для классов, где неявное преобразование из типа параметра в тип класса не имеет смысла или опасно (например, классы-обертки, "умные" указатели, контейнеры). Конструкторы std::vector с одним параметром size_t являются explicit, чтобы избежать случайного создания вектора из целого числа.