Вектор против строки
В чем принципиальное отличие, если оно есть, между С++ std::vector и std:: basic_string?
Ответы
Ответ 1
-
basic_string не вызывает конструкторы и деструкторы своих элементов. вектор делает.
-
swapping basic_string делает недействительными итераторы (разрешая небольшую оптимизацию строк), обменивающие векторы этого не делают.
-
Базовая память basic_string не может быть выделена непрерывно в С++ 03. вектор всегда непрерывный. Эта разница удаляется в С++ 0x [string.require]:
Объекты char -like в объекте basic_string сохраняются смежно
-
basic_string имеет интерфейс для строковых операций. вектор не имеет.
-
basic_string может использовать копию в стратегии записи (в pre С++ 11). вектор не может.
Релевантные цитаты для неверующих:
[basic.string]:
Шаблон класса basic_string соответствует требованиям для контейнера Sequence Container (23.2.3), для Реверсивный контейнер (23.2) и для контейнера, поддерживающего Allocator (Таблица 99), за исключением того, что basic_string не создает и не разрушает его элементы, используя allocator_traits:: construct и allocator_- черты:: destroy и что swap() для basic_string делает недействительными итераторы. Поддерживаемые итераторы by basic_string являются итераторами произвольного доступа (24.2.7).
Ответ 2
basic_string
предоставляет реализацию компилятора и стандартной библиотеки, несколько свобод над вектором:
-
"Маленькая оптимизация строк" действительна для строк, что позволяет реализациям сохранять фактическую строку, а не указатель на строку, в строчном объекте, когда строка короткая. Что-то вроде:
class string
{
size_t length;
union
{
char * usedWhenStringIsLong;
char usedWhenStringIsShort[sizeof(char*)];
};
};
-
В С++ 03 базовый массив не обязательно должен быть смежным. Внедрение basic_string
с точки зрения чего-то вроде "веревки" было бы возможно в соответствии с текущим стандартом. (Хотя никто этого не делает, потому что это сделает члены std::basic_string::c_str()
и std::basic_string::data()
слишком дорогими для реализации.)
С++ 11 теперь запрещает это поведение.
-
В С++ 03 basic_string
позволяет поставщику компилятора/библиотеки использовать функцию копирования-на-запись для данных (которые могут сохранять на копиях), что не разрешено для std::vector
. На практике это было гораздо более распространенным явлением, но в настоящее время оно менее распространено из-за воздействия, которое оно оказывает на многопоточность. В любом случае, ваш код не может полагаться на то, реализуется ли std::basic_string
с помощью COW.
С++ 11 снова запрещает это поведение.
Есть несколько вспомогательных методов, на которые накладывается basic_string
, но большинство из них просты и, конечно, могут быть легко реализованы поверх vector
.
Ответ 3
Ключевым отличием является то, что std::vector
должен хранить свои данные в непрерывной памяти, когда std::basic_string
не смог. В результате:
std::vector<char> v( 'a', 3 );
char* x = &v[0]; // valid
std::basic_string<char> s( "aaa" );
char* x2 = &s[0]; // doesn't point to continuous buffer
//For example, the behavior of
std::cout << *(x2+1);
//is undefined.
const char* x3 = s.c_str(); // valid
На практике это различие не так важно.
Ответ 4
Вектор представляет собой структуру данных, имитирующую массив. Глубоко внутри это фактически (динамический) массив.
Класс basic_string представляет последовательность символов. Он содержит все обычные операции последовательности и, кроме того, содержит стандартные операции с строкой, такие как поиск и конкатенация.
Вы можете использовать вектор, чтобы сохранить любой тип данных, который вы хотите std::vector<int> or <float> or even std::vector< std::vector<T> >
, но basic_string
может использоваться только для представления "текста".
Ответ 5
Basic_string предоставляет множество вариантов сравнения по строкам. Вы правы в том, что основной интерфейс управления памятью очень похож, но строка содержит много дополнительных элементов, таких как c_str(), что не имеет смысла для вектора.
Ответ 6
Единственное различие между std::string
и std::vector
заключается в том, что программы могут создавать строку из строки с нулевым завершением, тогда как с векторами они не могут.
std::string a = "hello"; // okay
std::vector<char> b = "goodbye"; // compiler error
Это часто упрощает работу с цепочками.
Ответ 7
TL;DR: string
оптимизированы, чтобы содержать только примитивы символов, vector
может содержать примитивы или объекты
Преобладающая разница между vector
и string
заключается в том, что vector
может корректно содержать объекты, string
работает только с примитивами. Таким образом, vector
предоставляет эти методы, которые были бы бесполезны для string
, работающего с примитивами:
Даже расширение string
не позволит ему правильно обрабатывать объекты, потому что в нем отсутствует деструктор. Это не следует рассматривать как недостаток, он позволяет значительно оптимизировать работу над vector
тем, что string
может:
Особенно важны char_traits::copy
, char_traits::move
и char_traits::assign
, очевидно, подразумевая, что будет использоваться прямое назначение, а не строительство или уничтожение, что опять же предпочтительнее для примитивов. Вся эта специализация имеет дополнительные недостатки string
, которые:
- Будут использоваться только теги
char
, wchar_t
, char16_t
или char32_t
. Очевидно, примитивы размером до 32 бит могут использовать их эквивалентный размер char_type
: fooobar.com/info/16873/..., но для примитивов, таких как long long
, новая специализация char_traits
нужно написать, а идея специализации char_traits::eof
и char_traits::not_eof
вместо использования vector<long long>
не похоже на лучшее использование времени.
- Из-за оптимизации коротких строк итераторы недействительны всеми операциями, которые сделали бы недействительным итератор
vector
, но итераторы string
дополнительно недействительны string::swap
и string::operator=
Дополнительные различия в интерфейсах vector
и string
:
- Нет измененного
string::data
: Почему не std::string.data() предоставляет изменяемый char *?
-
string
предоставляет функциональность для работы со словами, недоступными в vector
: string::c_str
, string::length
, string::append
, string::operator+=
, string::compare
, string::replace
, string::substr
, string::copy
, string::find
, string::rfind
, string::find_first_of
, string::find_first_not_of
, string::flind_last_of
, string::find_last_not_of
, string::operator+
, string::operator>>
, string::operator<<
, string::stoi
, string::stol
, string::stoll
, string::stoul
, string::stoull
, string::stof
, string::stod
, string::stold
, stirng::to_string
, string::to_wstring
- Наконец, везде
vector
принимает аргументы другого vector
, string
принимает string
или char*
Обратите внимание, что этот ответ написан на С++ 11, поэтому string
необходимо назначить смежно.