Как эффективно скопировать std :: string в вектор - PullRequest
2 голосов
/ 11 сентября 2011

У меня есть строка

std::string s = "Stack Overflow";

Это мне нужно скопировать в вектор. Вот как я это делаю

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' );

Но я слышал, что дальность действия более эффективна. Поэтому я думаю что-то вроде этого

std::vector<char> v( s.begin(), s.end());
v.push_back('\0');

Но лучше ли это в этом случае? Как насчет потенциального перераспределения при вставке '\ 0'?
Еще один подход, о котором я думаю, это

std::vector<char> v(s.length()+1);
std::strcpy(&v[0],s.c_str());

Возможно, быстро, но потенциально небезопасно?
EDIT
Должна быть строкой с нулевым символом в конце, которую можно использовать (чтение / запись) внутри функции C

Ответы [ 3 ]

6 голосов
/ 11 сентября 2011

Если вам действительно нужен вектор (например, потому что ваша функция C изменяет содержимое строки), то следующее должно дать вам то, что вы хотите, в одной строке:

std::vector<char> v(s.c_str(), s.c_str() + s.length() + 1);

Поскольку c_str() возвращает строку с нулевым символом в конце, вы можете просто скопировать ее целиком в вектор.

Однако я не совсем уверен, насколько оптимизирован этот конструктор.Я делаю знаю, что std::copy оптимизирован настолько, насколько это возможно, поэтому, возможно (измерить!) Следующее быстрее:

std::vector<char> v(s.length() + 1);
std::copy(s.c_str(), s.c_str() + s.length() + 1, v.begin());

Если функция C не изменяет строкуПросто пройдите c_str() напрямую и отбросьте постоянство.Это безопасно, , пока функция C читает только из строки.

3 голосов
/ 11 сентября 2011

В большинстве случаев вам не нужен вектор char, так как std::string в значительной степени является контейнером char. std::string также имеет функции begin и end. Также имеется функция c_str(), которая возвращает c-строку , которую вы можете передать любой функции, которая ожидает const char*, например:

void f(const char* str); //c-function

std::string s="some string";
f(s.c_str());

Так зачем вам нужен std::vector<char>?

На мой взгляд, vector<char> - это очень и очень редкая потребность, но если бы она мне когда-нибудь понадобилась, я бы, наверное, написал:

std::vector<char> v(s.begin(), s.end());

И для меня v.push_back('\0') не имеет особого смысла. Для вектора не требуется, чтобы последний элемент имел '\0', если value_type равно char.

Хорошо, как вы сказали, std::string::c_str() возвращает const char*, а функция c нуждается в неконстантном char*, тогда вы можете использовать std::vector, потому что вы хотите использовать RAII, который реализует вектор:

void g(char* s); //c-function

std::vector<char> v(s.begin(), s.end());
s.push_back('\0');

g(&v[0]);

что мне кажется нормальным. Но RAII - это все, что вам нужно, тогда у вас есть и другой вариант:

{
  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.

Используйте std::strcpy, std::memcpy или std::copy, какой бы ни был быстрый, так как я не могу сказать, какой из них обязательно быстрый, без профилирования.

0 голосов
/ 11 сентября 2011

Я не думаю, что std::strcpy(&v[0],s.c_str()); - хороший выбор. Я думаю, что c_str() разрешено перераспределять.

Если вам как-то «нужно» \0 для работы с C-API, тогда положитесь на string::c_str(), чтобы предоставить его вам по запросу. Не думайте, что вам нужно поместить его в вектор char, большинство вещей, которые вы можете сделать с самой строкой, как с вектором.

Обновление

Если вы убедитесь, что ваш вектор инициализирован с помощью 0 s, вы можете обойти вызов на c_str, используя strncopy:

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