Подтвердить что ты не робот

Почему std::string обеспечивает неявное преобразование в char *?

std::string предоставляет const char * c_str() const, который:

Получить эквивалент строки C

Генерирует нулевую последовательность символов (c-строка) с тем же содержимое как строковый объект и возвращает его как указатель на массив символы.

Конечный нулевой символ автоматически добавляется.

Возвращенный массив указывает на внутреннее местоположение с требуемым место для хранения этой последовательности символов плюс его завершение null-character, но значения в этом массив не должен изменяться в программы и предоставляются только на без изменений до следующего вызова не постоянная функция-член Строковый объект.

Почему бы просто не определить operator const char*() const {return c_str();}?

4b9b3361

Ответ 1

Из языка программирования С++ 20.3.7 (выделено мной):

Преобразование в строку стиля C могло быть предоставлено оператором const char *(), а не c_str(). Это обеспечило бы удобство неявного преобразования ценой неожиданностей в случаях, когда такое преобразование было неожиданным.

Ответ 2

Я вижу по крайней мере две проблемы с неявным преобразованием:

  • Даже явное преобразование, которое предоставляет c ___ str(), достаточно опасно, как есть. Я видел много случаев, когда указатель хранился для использования после того, как срок жизни исходного строкового объекта закончился (или объект был изменен, таким образом, недействительным указатель). С явным вызовом c_str() вы, надеюсь, знаете об этих проблемах. Но с неявным преобразованием было бы очень легко вызвать поведение undefined, как в:

    const char *filename = string("/tmp/") + name;
    ofstream tmpfile(filename); // UB
  • Преобразование также произойдет в некоторых случаях, когда вы не ожидаете этого, и семантика удивительна, если не сказать больше:

    string name;
    if (name) // always true
     ;
    name-2; // pointer arithmetic + UB
    These could be avoided by some means but why get into this trouble in the first place?

Ответ 3

В книге Йосуттиса говорится следующее:

Это по соображениям безопасности, чтобы предотвратить непреднамеренные преобразования типов, которые приводят к странному поведению (тип char * часто имеет странное поведение) и неоднозначностей (например, в выражении, которое объединяет string и C-строку, это можно преобразовать string в char * и наоборот).

Ответ 4

Потому что неявные преобразования почти никогда не ведут себя так, как вы ожидаете. Они могут дать неожиданные результаты при разрешении перегрузки, поэтому обычно лучше обеспечить явное преобразование, как это делает std::string.

Ответ 5

Вероятно, потому, что это преобразование имело бы удивительную и своеобразную семантику. В частности, приведенный вами четвертый абзац.

Другая причина заключается в том, что существует неявное преобразование const char* -> string, и это было бы просто обратным, что означало бы странное поведение при разрешении перегрузки (вы не должны делать как неявные преобразования A->B, так и B->A).

Ответ 6

В дополнение к обоснованию, указанному в спецификации (неожиданные сюрпризы), если вы смешиваете вызовы API C с помощью std::string, вам действительно нужно привыкнуть использовать метод:: c_ctr(). Если вы когда-либо вызываете функцию varargs (например: printf или ее эквивалент), которая требует const char *, и вы передаете std::string напрямую (без вызова метода извлечения), вы не получите ошибку компиляции (нет тип проверки для функций varargs), но вы получите ошибку времени выполнения (макет класса не является бинарным, идентичным const char *).

Кстати, CString (в MFC) использует противоположный подход: он имеет неявный листинг, а макет класса двоично-совместим с const char * (или const w_char *, если компилируется для широких символов, то есть: "Unicode" ).

Ответ 7

Поскольку строки в стиле C являются источником ошибок и многих проблем безопасности, лучше сделать преобразование явно.