char* против std::string в С++ [закрыто]
Вопрос
Когда мне следует использовать std::string
и когда мне следует использовать char*
управлять массивами char
s на С++?
Кажется, вам следует использовать char*
если производительность (скорость) имеет решающее значение, и вы готовы пойти на рискованный бизнес из-за управления памятью.
Есть ли другие сценарии, которые стоит рассмотреть?
Решение
Вы можете передавать std::strings по ссылке, если они большие, чтобы избежать копирования, или указатель на экземпляр, поэтому я не вижу никакого реального преимущества в использовании указателей char.
Я использую std::string/wstring более или менее для всего, что представляет собой настоящий текст. char *
Тем не менее, это полезно для других типов данных, и вы можете быть уверены, что они будут освобождены так, как и должны.В противном случае лучше всего использовать std::vector.
Вероятно, из всего этого есть исключения.
Другие советы
Моя точка зрения такова:
- Никогда не используйте char *, если вы не вызываете код «C».
- Всегда используйте std::string:Это проще, более дружелюбно, оптимизировано, стандартно, предотвращает возникновение ошибок, проверено и доказало свою эффективность.
Использование необработанной строки
Да, иногда это действительно можно сделать.При использовании const char *, массивов символов, выделенных в стеке, и строковых литералов вы можете сделать это таким образом, чтобы вообще не выделялось памяти.
Написание такого кода зачастую требует большего обдумывания и внимательности, чем использование строки или вектора, но при наличии соответствующих методов это можно сделать.При правильном подходе код может быть безопасным, но вы всегда должны быть уверены, что при копировании в char[] у вас либо есть некоторые гарантии относительно длины копируемой строки, либо вы изящно проверяете и обрабатываете строки слишком большого размера.Невыполнение этого требования дало семейству функций strcpy репутацию небезопасных.
Как шаблоны могут помочь в написании безопасных буферов символов
Что касается безопасности буферов char[], шаблоны могут помочь, поскольку они могут создать инкапсуляцию для обработки размера буфера за вас.Подобные шаблоны реализованы, например.Microsoft, чтобы предоставить безопасную замену strcpy.Пример здесь взят из моего собственного кода, в реальном коде гораздо больше методов, но этого должно быть достаточно, чтобы передать основную идею:
template <int Size>
class BString
{
char _data[Size];
public:
BString()
{
_data[0]=0;
// note: last character will always stay zero
// if not, overflow occurred
// all constructors should contain last element initialization
// so that it can be verified during destruction
_data[Size-1]=0;
}
const BString &operator = (const char *src)
{
strncpy(_data,src,Size-1);
return *this;
}
operator const char *() const {return _data;}
};
//! overloads that make conversion of C code easier
template <int Size>
inline const BString<Size> & strcpy(BString<Size> &dst, const char *src)
{
return dst = src;
}
Один случай, который вы ДОЛЖНЫ использовать char*
и не std::string
это когда вам нужны статические строковые константы.Причина этого в том, что вы не имеете никакого контроля над тем, как модули инициализируют свои статические переменные, и другой глобальный объект из другого модуля может ссылаться на вашу строку до ее инициализации. http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Static_and_Global_Variables
std::string
плюсы:
- управляет памятью за вас (строка может расти, и реализация выделит вам больший буфер)
- Интерфейс программирования более высокого уровня, хорошо работает с остальной частью STL.
std::string
минусы:— два разных экземпляра строки STL не могут использовать один и тот же базовый буфер.Поэтому, если вы передаете по значению, вы всегда получаете новую копию.- есть некоторое снижение производительности, но я бы сказал, что если у вас нет особых требований, оно незначительно.
Вам следует рассмотреть возможность использования char*
в следующих случаях:
- Этот массив будет передан в качестве параметра.
- Вы заранее знаете максимальный размер вашего массива (вы знаете его ИЛИ накладываете его).
- Вы не будете выполнять никаких преобразований в этом массиве.
На самом деле в С++ char*
часто используются для фиксированных небольших слов, таких как параметры, имя файла и т. д.
Когда использовать c++ std::string:
- строки в целом более безопасны, чем char*. Обычно, когда вы делаете что-то с char*, вам нужно все проверить, чтобы убедиться, что все правильно, в классе строк все это делается за вас.
- Обычно при использовании char* вам придется освободить выделенную память, вам не нужно делать это со строкой, поскольку она освободит свой внутренний буфер при разрушении.
- Строки хорошо работают со строковым потоком C++, форматировать ввод-вывод очень просто.
Когда использовать символ*
- Использование char* дает вам больше контроля над тем, что происходит «за кулисами», а это означает, что вы можете настроить производительность, если вам нужно.
Используйте (const) char* в качестве параметров, если вы пишете библиотеку.Реализации std::string различаются в разных компиляторах.
Если вы хотите использовать библиотеки C, вам придется иметь дело с C-строками.То же самое применимо, если вы хотите предоставить свой API C.
Вы можете ожидать, что большинство операций над std::string (например, find
), чтобы быть максимально оптимизированными, поэтому они, скорее всего, будут работать как минимум так же хорошо, как и аналог на чистом C.
Также стоит отметить, что итераторы std::string довольно часто сопоставляются с указателями на базовый массив символов.Таким образом, любой алгоритм, который вы разрабатываете поверх итераторов, по сути идентичен тому же алгоритму поверх char * с точки зрения производительности.
На что следует обратить внимание, например. operator[]
- большинство реализаций STL не выполняют проверку границ и должны преобразовать ее в ту же операцию с базовым массивом символов.AFAIK STLPort может дополнительно выполнять проверку границ, после чего этот оператор будет работать немного медленнее.
Так что же вам дает использование std::string?Это освобождает вас от ручного управления памятью;изменить размер массива становится проще, и вам вообще придется меньше думать об освобождении памяти.
Если вас беспокоит производительность при изменении размера строки, есть reserve
функция, которая может оказаться вам полезной.
если вы используете массив символов в виде текста и т.д.используйте std::string более гибко и проще в использовании.Если вы используете его для чего-то другого, например для хранения данных?использовать массивы (предпочитаю векторы)
Даже когда производительность имеет решающее значение, лучше использовать vector<char>
- он позволяет заранее выделить память (метод Reserve()) и поможет избежать утечек памяти.Использование вектора::operator[] приводит к дополнительным затратам, но вы всегда можете извлечь адрес буфера и проиндексировать его точно так же, как если бы это был символ char*.
AFAIK внутри большинства std::string реализует копирование при записи, семантику с подсчетом ссылок, чтобы избежать накладных расходов, даже если строки не передаются по ссылке.