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?
10 Answers
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());
2 Comments
I think you can just do
std::string s( MyVector.begin(), MyVector.end() );
where MyVector is your std::vector.
1 Comment
_ITERATOR_DEBUG_LEVEL=1 (in which case it seems to work fine).You can do std::string(v.data(), v.size()), or if you're entirely certain your vector is null terminated, you can simply use std::string(v.data())
5 Comments
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.std::string(v.data()) might lead a longer string. So do not use this way.std::string(v.data(), v.size()), which was explicitly mentioned in the answer for that exact reason?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".
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().
4 Comments
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).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.)Just for code demonstration:
#include <iostream>
#include <string>
#include <vector>
int main() {
    std::vector<char> v1 {'l', 'o', 'v', 'e', '\0', '\0', '\0'};
    std::vector<char> v2 {'l', 'o', 'v', 'e', '\0', '\0', '\0', 'y', 'o', 'u'};    
    for (auto & v : {v1, v2}){
        std::string s1(v.cbegin(), v.cend());   
        std::cout << s1 << "|---" << s1.size() << '\n';    
        std::string s2(v.data());
        std::cout << s2 << "|---" << s2.size() << '\n';        
        std::string s3(&v[0]);
        std::cout << s3 << "|---" << s3.size() << '\n';
        std::string s4(v.data(), v.size());
        std::cout << s4 << "|---" << s4.size() << '\n';
        std::string s5(&v[0], v.size());
        std::cout << s5 << "|---" << s5.size() << '\n';
        std::cout << '\n';
    }    
}
Output:
love|---7
love|---4
love|---4
love|---7
love|---7
loveyou|---10
love|---4
love|---4
loveyou|---10
loveyou|---10
Comments
vector<char> vec;
//fill the vector;
std::string s(vec.begin(), vec.end());
5 Comments
Interesting that the initializer list has not been mentioned yet
std::string s{v.begin(), v.end()}
According to Nicolai Josuttis
The brace initialization has the following advantages:
•It can be used with fundamental types, class types, aggregates, enumeration types, and auto
• It can be used to initialize containers with multiple values
• It can detect narrowing errors (e.g., initialization of an int by a floating-point value)
• It cannot be confused with function declarations or calls
• If the braces are empty, the default constructors of (sub)objects are called and fundamental data types are guaranteed to be initialized with 0 / false / nullptr
Comments
To bring this up to C++23, use ranges::to<>(), which will also handle any range (container). It also handles embedded zeros.
#include <ranges>
#include <string>
#include <vector>
namespace rng = std::ranges;
namespace vws = std::views;
#include <fmt/ranges.h>
using fmt::println, fmt::print;
auto main(int, char**) -> int {
   std::vector<char> v1 {'l', 'o', 'v', 'e', '\0', '\0', '\0'};
   std::string s1 = v1 | rng::to<std::string>();
   println("{}", s1);
   std::vector<char> v2 {'l', 'o', 'v', 'e', '\0', '\0', '\0', 'y', 'o', 'u'};
   std::string s2 = v2 | rng::to<std::string>();
   println("{}", s2);
   return 0;
}







std::vector<char> v2(std::move(v))but with astd::stringas the new object.