Как построить std :: string из std :: vector <char>?

115

Если не считать (очевидного) сначала создания строки в стиле C, а затем ее использования для создания std :: string, есть ли более быстрый / альтернативный / «лучший» способ инициализировать строку из вектора символов?

oompahloompah
источник
4
Можно ли это сделать без копирования? Другими словами, что-то, что делает то же самое, std::vector<char> v2(std::move(v))но с std::stringновым объектом.
tobi_s 02

Ответы:

197

Что ж, лучше всего использовать следующий конструктор:

template<class InputIterator> string (InputIterator begin, InputIterator end);

что приведет к чему-то вроде:

std::vector<char> v;
std::string str(v.begin(), v.end());
Greg
источник
41

Я думаю, ты можешь просто сделать

std::string s( MyVector.begin(), MyVector.end() );

где MyVector - это ваш std :: vector.

LiMuBei
источник
1
За исключением VS2013, который утверждает во время выполнения о недопустимых итераторах, если вы не установили _ITERATOR_DEBUG_LEVEL=1(в этом случае, похоже, все работает нормально).
Кэмерон
35

В C ++ 11 вы можете сделать std::string(v.data())или, если ваш вектор не содержит '\0'в конце std::string(v.data(), v.size()),.

Штефана
источник
Я считаю, что даже с C ++ 98 можно использовать std :: string (& v [0]). Это, конечно, если вектор заканчивается нулем.
Джейми
1
@Jamie: Кстати, в C ++ 98 string(&v[0], v.size())тоже должно работать, но только после assert(not v.empty());, поскольку, если вектор пуст, оба v[0]и v.front()будут вызывать неопределенное поведение. В этом, помимо синтаксической простоты отсутствия использования оператора адресации, является реальное преимущество функции C ++ 11 data(), которая работает даже с пустым вектором.
Адам Х. Петерсон,
Совершенно верно. К сожалению, в обозримом будущем мой проект застрял на Visual Studio 2008. Правильно сначала проверить длину вектора.
Джейми
Если вектор не содержит '\ 0', std::string(v.data())строка может быть длиннее. Так что не используйте этот способ.
heLomaN
@heLomaN: Что случилось с тем std::string(v.data(), v.size()), что было прямо упомянуто в ответе именно по этой причине?
Sz.
12
std::string s(v.begin(), v.end());

Где v практически все, что можно итерировать. (В частности, begin () и end () должны возвращать InputIterators.)

Мартин Стоун
источник
3

Для полноты можно использовать другой способ std::string(&v[0])(хотя вам нужно убедиться, что ваша строка заканчивается нулем, и std::string(v.data())обычно это предпочтительнее.

Разница в том, что вы можете использовать предыдущий метод для передачи вектора функциям, которые хотят изменить буфер, чего вы не можете сделать с .data ().

буйство
источник
Почему нельзя использовать data()для изменения буфера? Мне кажется, что если вы вызываете data()неконстантный вектор, он вернет a T *(и если ваш вектор const, 'v [0] `все T const &равно вернет a ).
Адам Х. Петерсон,
@ AdamH.Peterson это вроде недосмотр в стандарте. Данные Std :: vector имеют как константные, так и неконстантные функции, тогда как в текущем стандарте std :: string имеет только константную функцию: en.cppreference.com/w/cpp/string/basic_string/data Обратите внимание, что C ++ 17 добавляет неконстантную версию, так что это не может быть так до бесконечности - однако текущий стандарт гласит: «Изменение массива символов, доступ к которому осуществляется через данные, имеет неопределенное поведение».
Riot
Это было бы верно, если бы vэто была строка, но целевой тип - это строка и vвектор. (Но приятно видеть, что C ++ 17 обеспечивает четность строк с вектором.)
Адам Х. Петерсон,
@ AdamH.Peterson, конечно, ты прав. На вопрос был дан ответ некоторое время назад, я предполагал, что весь вопрос касается исключительно строк без проверки.
Riot
2

Мне нравится ответ Стефана (11 сентября 2013 г.), но я хотел бы сделать его немного сильнее:

Если вектор заканчивается нулевым ограничителем, вы не должны использовать (v.begin (), v.end ()): вы должны использовать v.data () (или & v [0] для тех, кто был до C ++ 17) ,

Если v не имеет нулевого терминатора, вы должны использовать (v.begin (), v.end ()).

Если вы используете begin () и end () и вектор действительно имеет завершающий ноль, вы получите, например, строку «abc \ 0», которая имеет длину 4, но на самом деле должна быть только «abc».

Анри Раат
источник
1
vector<char> vec;
//fill the vector;
std::string s(vec.begin(), vec.end());
TechCat
источник
Не могли бы вы добавить пояснения, а также код?
Пол Флойд
1
Шаблон строковой библиотеки C ++ 11 выглядит следующим образом: default (1) string (); copy (2) строка (const string & str); substring (3) строка (const string & str, size_t pos, size_t len ​​= npos); from c-string (4) строка (const char * s); из буфера (5) строка (const char * s, size_t n); fill (6) строка (size_t n, char c); диапазон (7) шаблон <класс InputIterator> строка (сначала InputIterator, затем - InputIterator); список инициализаторов (8) строка (initializer_list <char> il); move (9) строка (строка && str) noexcept; мы следуем 7-му шаблону.
TechCat
Привет, @TechCat! Пожалуйста, прочтите, как написать хороший ответ, прежде чем отвечать на следующий вопрос. Наслаждайтесь пребыванием в SO!
Дигги.
Не могли бы вы отредактировать свой ответ с описанием?
Пол Флойд