Почему std :: string не обеспечивает неявное преобразование в char *? - PullRequest
25 голосов
/ 29 января 2009

std::string обеспечивает const char * c_str () const , который:

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

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

Завершающий нулевой символ автоматически добавляется.

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

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

Ответы [ 7 ]

22 голосов
/ 29 января 2009

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

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

15 голосов
/ 29 января 2009

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

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

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

    <code>string name;
    if (name) // always true
     ;
    name-2; // pointer arithmetic + UB
    Этого можно избежать какими-то способами, но зачем вообще попадать в эту проблему?
5 голосов
/ 29 января 2009

Книга Иосуттиса гласит:

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

4 голосов
/ 29 января 2009

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

3 голосов
/ 29 января 2009

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

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

2 голосов
/ 29 января 2009

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

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

1 голос
/ 29 января 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...