Як побудувати 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.