简体   繁体   中英

How to efficiently copy a std::string into a vector

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 this

std::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

If you really need a vector (eg 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.

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.

I don't think std::strcpy(&v[0],s.c_str()); is a good choice. I think c_str() is allowed to re-allocate.

If you somehow "need" the \\0 for dealing with C-APIs, then rely on string::c_str() to provide it to you, on request. In dont think that you need to put it into a vector-of-char, most things you can do with the string itself like with a vector.

Update :

If you make sure your vector gets initialized with 0 s, you can circumvent the call to c_str by using strncopy :

std::vector<char> v(s.length()+1, 0);  // added '0'
std::strncpy(&v[0],&s[0],s.length());  // no c_str()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM