Як побудувати std :: string з std :: vector <char>?


115

За винятком (очевидного) побудови рядка стилю C спочатку, використовуючи це для створення std :: string, чи існує швидший / альтернативний / "кращий" спосіб ініціалізації рядка з вектора символів?


4
Чи можна це зробити без копіювання? Іншими словами, те, що робить те саме, що і std::vector<char> v2(std::move(v))з std::stringновим об'єктом.
tobi_s

Відповіді:


197

Ну, найкращим способом є використання наступного конструктора:

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

що призведе до чогось типу:

std::vector<char> v;
std::string str(v.begin(), v.end());

41

Я думаю, ти можеш просто зробити

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

де MyVector - ваш std :: vector.


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 майже все, що можна відтворити. (Спеціально start () та end () повинні повернути InputIterators.)


3

Для повноти, інший спосіб є std::string(&v[0])(хоча вам потрібно переконатися, що ваш рядок є недійсним і, std::string(v.data())як правило, бажано.

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


Чому ви не можете використовувати data()для зміни буфера? Мені це здається, якщо ви зателефонуєте data()за неконст-вектором, він поверне a T *(а якщо ваш вектор const, 'v [0] `повернеться у T const &будь-якому випадку).
Адам Х. Петерсон

@ AdamH.Peterson це здається наглядом у стандарті. Дані Std :: вектор мають як const, так і non-const функції, тоді як у поточному стандарті std :: string має лише функцію const: en.cppreference.com/w/cpp/string/basic_string/data Зверніть увагу, що C ++ 17 додає версію non-const, тож це може бути не так нескінченно - однак, чинний стандарт говорить: "Модифікація масиву символів, доступ до яких здійснюється через дані, має невизначене поведінку".
Бунт

Це було б правдою, якби це vбув рядок, але цільовий тип - це рядок і vє вектором. (Але приємно бачити, що C ++ 17 дасть рядки парності з вектором.)
Адам Х. Петерсон,

@ AdamH.Peterson ти прав, звичайно. На це питання відповіли деякий час тому, я вважав, що все питання стосується рядків виключно без перевірки.
Бунт

2

Мені подобається відповідь Стефана (11 вересня 1313 р.), Але я хотів би зробити її трохи сильнішою:

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

Якщо v не має нульового термінатора, слід використовувати (v.begin (), v.end ()).

Якщо ви використовуєте start () і end (), а вектор має кінцевий нуль, ви отримаєте рядок "abc \ 0", наприклад, довжиною 4, але насправді має бути лише "abc".


1
vector<char> vec;
//fill the vector;
std::string s(vec.begin(), vec.end());

Чи можете ви додати деякі пояснення, а також код?
Пол Флойд

1
Шаблон бібліотеки рядків C ++ 11 йде наступним чином (1) string (); copy (2) рядок (string const & str); substring (3) рядок (const string & str, size_t pos, size_t len ​​= npos); з 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) (inicijalizer_list <char> il); move (9) string (string && str) noexcept; ми слідуємо 7-му шаблону.
TechCat

Привіт @TechCat! Будь ласка, прочитайте, як написати хорошу відповідь, перш ніж відповісти на наступне запитання. Приємного перебування в SO!
Діггі.

Чи можете ви відредагувати свою відповідь описом?
Пол Флойд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.