Когда следует использовать std::string по массивам символов?
Я сижу и думаю о том, нужно ли мне часто использовать const char*
или const std::string&
, когда я разрабатываю интерфейсы классов, и когда дело доходит до него, я часто чувствую, что там 6 в одной руке с полдюжины в другом.
Возьмите следующие два прототипа функций:
void foo(const char* str);
void foo(std::string str);
Если функция foo
должна была хранить строку, я бы сказал, что вторая - лучший вариант из-за способности передавать строку и использовать семантику перемещения, где это возможно. Однако, если foo
нужно было только прочитать строку, было бы лучше решение const char*
?
С точки зрения производительности временный std::string
не нужно создавать. Однако вызов функции с уже существующей строкой в качестве аргумента выглядит навязчивым: foo(mystr.c_str())
. Хуже того, если более сложные операции необходимо выполнить в массиве в какой-то момент по дороге или если копия должна быть сохранена, тогда интерфейс должен измениться.
Итак, мои вопросы таковы:
Есть ли четко определенные, личные или иные соглашения, которые правило, когда std::string
или const char*
является лучшим выбором? Кроме того, при запуске нового проекта лучше всего быть совместимым с использованием или просто взять тот, который лучше всего подходит для текущего фрагмента кода?
Ответы
Ответ 1
const char*
- это возврат к C. Я бы сказал, что в приличном С++ о единственном использовании для него есть API extern "C"
.
std::string
имеет ряд преимуществ:
-
Он обеспечивает постоянную функцию size()
. Обнаружение длины const char*
занимает линейное время.
-
Гарантируется, что оно будет действительным. A const char*
должен быть проверен на то, что он является нулевым, и вполне возможно передать неверные данные - данные не имеют нулевого терминатора. Такое появление в значительной степени гарантировано приведет к краху или к худшему.
-
Он совместим со стандартными алгоритмами.
Если вы беспокоитесь о влиянии производительности на создание std::string
для вызова функции, рассмотрите подход, который использует стандартная библиотека - замените функцию на использование пары итераторов. Затем вы можете обеспечить удобную перегрузку с помощью делегирования const std::string&
на пару итератор-пар.
Ответ 2
Всего несколько заметок из личного опыта. Если вы работаете над проектом С++ (в соответствии с добавленным тегом), приложите к std::string
столько, сколько сможете. Не пытайтесь изобрести самую основную из всех структур, всемогущую строку. Я видел несколько проектов, в которых они заново изобрели базовую строку, а затем потратили месяцы, чтобы ее настроить.
В случае вашего проекта С++ с момента ввода переменной char*
вы возвращаетесь к стандартным функциям C, таким как strlen()
и strcpy
(просто для обозначения двух...). И с этого момента ваш проект начинает превращаться в беспорядок, с распределением памяти с ручным управлением и т.д.
Если вам нужно взаимодействовать с сторонними библиотеками, которые принимают const char*
в качестве своего параметра (и я полагаю, что вы доверяете этим библиотекам, то есть: вы доверяете, что они не const_cast
отстоят от вас, чтобы делать зло с вашими бедными string) вы можете использовать std::string::c_str()
, чтобы вывести const char*
из вашей строки.
Если вам нужно взаимодействовать с библиотеками, у которых есть методы, принимающие char*
, я настоятельно рекомендую вам взять копию вашей строки c_str()
и использовать ее как входящий параметр в библиотеку (конечно, не забудьте удалить дополнительная копия).
Помимо этих дополнительных точек я просто подписался на все три точки из ответа Ангела.
Ответ 3
std::string
всегда должен быть первым выбором в С++. Чтобы избежать дополнительных накладных расходов на копирование, вы должны почти всегда передавать аргумент как ссылочный и const
справочный материал и, когда это возможно.
В этом случае ваша подпись функции будет выглядеть следующим образом
void foo (std::string & str);
и вот так, если аргумент const
void foo (const std::string & str);
Здесь есть преимущества этого ключевого слова const, которое вы можете посмотреть здесь
Ответ 4
std::string лучше, чем использование raw char *, где вам нужно управлять распределением, деаллокациями и проблемой с размером, чтобы быть осторожным при любом переполнении, underflow, что вы не пересекаете границу размера. В то время как std::string все они заботятся об абстракции
Ответ 5
Вместо использования
void foo(std::string str);
вы можете использовать
void foo(const std::string& str);
который будет эквивалентен
void foo(const char* str);
с точки зрения использования, поскольку при передаче ссылки не выделяется память. Но для строк в С++ я бы определенно использовал std::string
. Для случайных данных или совместимых с C интерфейсов я бы не стал.
Ответ 6
Если вам нужна более эффективная обработка ваших данных (в вашем случае это будет строка), я бы сказал, перейдите с char *. Это даст вам лучший доступ к использованию вашей строки и памяти.
Но если вам не нужно беспокоиться о производительности и проблемах с управлением памятью, вы можете легко использовать std::string.
Ответ 7
Хорошо, я бы немного перефразировал ваш вопрос. Вы должны спросить, следует ли использовать массив символов вместо std::string
.
Это потому, что вы всегда должны использовать string
, если вы не можете его использовать. Поэтому в ситуациях, когда вы должны использовать массив символов вместо string
:
- Использование API-интерфейсов, поддерживающих
C
, поэтому вы не можете использовать string
.
- Передача данных между
exe
и dll
. Не рекомендуется обменивать типы данных, которые имеют конструктор и/или деструктор между exe
и dll
Если вы беспокоитесь о производительности, то после компиляции с включенными всеми оптимизациями string
становится похожим на массив символов, возможно, дает в некоторых случаях даже лучшую производительность, например, если вам нужно получить количество содержащихся в нем символов.
Также о производительности вы всегда можете передавать по ссылке, как упоминалось в других ответах, если вам нужно передать указатель на массив символов, вы можете использовать метод c_str()
, который возвращает указатель const
на первый символ, если вы нужно передать указатель (не const
указатель), вы можете (но на самом деле не должны) передать его следующим образом: &str[0]
.