How to efficiently copy a std::string into a vector
Solution 1
If you really need a vector (e.g. because your C function modifies the string content), then the following should give you what you want, in one line:
std::vector<char> v(s.c_str(), s.c_str() + s.length() + 1);
Since c_str()
returns a null-terminated string, you can just copy it whole into the vector.
However, I’m not actually sure how optimised this constructor is. I do know that std::copy
is as optimised as it gets, so perhaps (measure!) the following is faster:
std::vector<char> v(s.length() + 1);
std::copy(s.c_str(), s.c_str() + s.length() + 1, v.begin());
If the C function doesn’t modify the string, just pass c_str()
directly, and cast away const-ness. This is safe, as long as the C function only reads from the string.
Solution 2
In most cases, you don't need vector of char
, as std::string
pretty much is a container of char
. std::string
also have begin
and end
functions. And it also have c_str()
function which returns the c-string which you can pass to any function which expects const char*
, such as this:
void f(const char* str); //c-function
std::string s="some string";
f(s.c_str());
So why would you ever need std::vector<char>
?
In my opinion, vector<char>
is a very very rare need but if I ever need it, I would probably write this:
std::vector<char> v(s.begin(), s.end());
And to me, v.push_back('\0')
doesn't make much sense. There is no such requirement on vector to have the last element as '\0'
if the value_type
is char
.
Alright, as you said, std::string::c_str()
returns const char*
, and the c-function needs a non-const char*
, then you can use std::vector
because you want to take advantage of RAII which vector implements:
void g(char* s); //c-function
std::vector<char> v(s.begin(), s.end());
s.push_back('\0');
g(&v[0]);
which seems fine to me. But RAII is all that you need, then you've other option as well:
{
std::vector<char> memory(s.size()+1);
char *str = &memory[0]; //gets the memory!
std::strcpy(str, s.c_str());
g(str);
//....
} //<--- memory is destroyed here.
Use std::strcpy
, std::memcpy
or std::copy
whichever is fast, as I cannot say which one is necessarily fast, without profiling.
molita
Updated on June 05, 2022Comments
-
molita almost 2 years
I have a string
std::string s = "Stack Overflow";
That I need to copy into a vector. This is how I am doing it
std::vector<char> v; v.reserve(s.length()+1); for(std::string::const_iterator it = s.begin(); it != s.end(); ++it) { v.push_back( *it ); } v.push_back( '\0' );
But I hear range operation are more efficient. So I am thinking something like this
std::vector<char> v( s.begin(), s.end()); v.push_back('\0');
But is this better in this case? What about the potential re-allocation when inserting '\0'?
Another approach I am thinking is thisstd::vector<char> v(s.length()+1); std::strcpy(&v[0],s.c_str());
Perhaps fast but potentially unsafe?
EDIT
Has to be a null terminated string that can be used ( read/write ) inside a C function