139

Short of (the obvious) building a C style string first then using that to create a std::string, is there a quicker/alternative/"better" way to initialize a string from a vector of chars?

oompahloompah
  • 9,087
  • 19
  • 62
  • 90
  • 6
    Can this be done without copying? In other words something which does the same thing as `std::vector v2(std::move(v))` but with a `std::string` as the new object. – tobi_s Oct 02 '18 at 03:17

8 Answers8

234

Well, the best way is to use the following constructor:

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

which would lead to something like:

std::vector<char> v;
std::string str(v.begin(), v.end());
sanyassh
  • 8,100
  • 13
  • 36
  • 70
Greg
  • 6,038
  • 4
  • 22
  • 37
48

I think you can just do

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

where MyVector is your std::vector.

Martin York
  • 257,169
  • 86
  • 333
  • 562
LiMuBei
  • 2,868
  • 22
  • 27
  • 2
    Except in VS2013 which asserts at runtime about invalid iterators, unless you set `_ITERATOR_DEBUG_LEVEL=1` (in which case it seems to work fine). – Cameron Sep 23 '14 at 22:39
44

With C++11, you can do std::string(v.data()) or, if your vector does not contain a '\0' at the end, std::string(v.data(), v.size()).

Ștefan
  • 728
  • 5
  • 7
  • Even with C++98, I believe you can do std::string(&v[0]). This, of course, is if the vector is null-terminated. – Jamie Apr 16 '16 at 00:48
  • 2
    @Jamie: By the way, in C++98, `string(&v[0], v.size())` should work also, but only after `assert(not v.empty());`, since if the vector is empty, both `v[0]` and `v.front()` would invoke undefined behavior. That, aside from the syntactic simplicity of not having to use the address-of operator, is the real benefit of C++11's `data()` function, which works even on an empty vector. – Adam H. Peterson Apr 25 '16 at 19:46
  • Very true. Unfortunately, my project is stuck on Visual Studio 2008 for the foreseeable future. Right about checking vector length first. – Jamie May 02 '16 at 17:51
  • 1
    If vector does not contain a '\0', `std::string(v.data())` might lead a longer string. So do not use this way. – heLomaN Nov 20 '18 at 12:53
  • @heLomaN: What's wrong with `std::string(v.data(), v.size())`, which was explicitly mentioned in the answer for that exact reason? – Sz. Aug 13 '19 at 11:50
12
std::string s(v.begin(), v.end());

Where v is pretty much anything iterable. (Specifically begin() and end() must return InputIterators.)

Martin Stone
  • 12,682
  • 2
  • 39
  • 53
7

I like Stefan’s answer (Sep 11 ’13) but would like to make it a bit stronger:

If the vector ends with a null terminator, you should not use (v.begin(), v.end()): you should use v.data() (or &v[0] for those prior to C++17).

If v does not have a null terminator, you should use (v.begin(), v.end()).

If you use begin() and end() and the vector does have a terminating zero, you’ll end up with a string "abc\0" for example, that is of length 4, but should really be only "abc".

Henri Raath
  • 71
  • 1
  • 2
4

Just for completeness, another way is std::string(&v[0]) (although you need to ensure your string is null-terminated and std::string(v.data()) is generally to be preferred.

The difference is that you can use the former technique to pass the vector to functions that want to modify the buffer, which you cannot do with .data().

Riot
  • 15,723
  • 4
  • 60
  • 67
  • Why can't you use `data()` to modify the buffer? It looks to me like if you call `data()` on a non-const vector, it will return a `T *` (and if your vector is const, 'v[0]` would return a `T const &` anyway). – Adam H. Peterson Apr 25 '16 at 19:42
  • @AdamH.Peterson it seems to be an oversight in the standard. Std::vector's data has both const and non-const functions, whereas in the current standard, std::string has only a const function: http://en.cppreference.com/w/cpp/string/basic_string/data Note that C++17 adds a non-const version, so this may not be the case indefinitely - however, the current standard states "Modifying the character array accessed through data has undefined behavior." – Riot Apr 26 '16 at 16:48
  • That would be true if `v` were a string, but the target type is a string and `v` is a vector. (But it is nice to see that C++17 will give strings parity with vector.) – Adam H. Peterson Apr 26 '16 at 16:51
  • @AdamH.Peterson you're right of course. The question was answered a while ago, I'd assumed the whole question was about strings exclusively without checking. – Riot Apr 26 '16 at 17:44
0
vector<char> vec;
//fill the vector;
std::string s(vec.begin(), vec.end());
TechCat
  • 57
  • 1
  • Could you add some explanations as well as the code? – Paul Floyd May 13 '20 at 14:46
  • 1
    C++11 string library template goes as follows default (1) string(); copy (2) string (const string& str); substring (3) string (const string& str, size_t pos, size_t len = npos); from c-string (4) string (const char* s); from buffer (5) string (const char* s, size_t n); fill (6) string (size_t n, char c); range (7) template string (InputIterator first, InputIterator last); initializer list (8) string (initializer_list il); move (9) string (string&& str) noexcept; we are following 7th template. – TechCat May 13 '20 at 15:27
  • Hi @TechCat! Please read up on [writing a good answer](https://stackoverflow.com/help/how-to-answer) before answering your next question. Enjoy your stay at SO! – Diggy. May 13 '20 at 15:49
  • Could you edit your answer with the description please? – Paul Floyd May 13 '20 at 18:41
  • Not sure why this was down voted, this is a perfectly acceptable answer. – Jamie Nicholl-Shelley Jan 04 '22 at 00:57
0

Just for code demonstration:

    std::vector<char> vc {'l', 'o', 'v', 'e', '\0', '\0', '\0'};
    std::string sCat(vc.cbegin(), vc.cend());   
    std::cout << sCat << "|---" << '\n';
    std::cout << sCat.size() << "|---" << '\n';
    std::cout << "------------" << '\n';
    std::string sCat2(vc.data());
    std::cout << sCat2 << "|---" << '\n';
    std::cout << sCat2.size() << "|---" << '\n';
    std::cout << "------------" << '\n';
    std::string sCat3(&vc[0]);
    std::cout << sCat3 << "|---" << '\n';
    std::cout << sCat3.size() << "|---" << '\n';
    std::cout << "------------" << '\n';

Output:

love|---
7|---
------------
love|---
4|---
------------
love|---
4|---
------------
starriet
  • 2,565
  • 22
  • 23