Как перебрать std :: vector <char>и найти c-строки с нулевым символом в конце - PullRequest
0 голосов
/ 16 сентября 2011

У меня три вопроса на основе следующих фрагментов кода
У меня есть список строк.Это просто случайный вектор, но он может быть любым источником

vector<string> v1_names = boost::assign::list_of("Antigua and Barbuda")( "Brasil")( "Papua New Guinea")( "Togo");

Ниже следует хранить длины каждого имени

vector<int> name_len;

, вот где я хочусохранить строки

std::vector<char> v2_names;

оценка памяти, необходимой для копирования имен из v1_names

v2_names.reserve( v1_names.size()*20 + 4 );

Вопрос: это лучший способ оценкиместо хранения?Я исправляю max len на 20, что нормально, затем добавляю место для нулевого тремонатора
Теперь скопируем имена

for( std::vector<std::string>::size_type i = 0; i < v1_names.size(); ++i)
{
    std::string val( v1_names[i] );
    name_len.push_back(val.length());
    for(std::string::iterator it = val.begin(); it != val.end(); ++it)
    {
        v2_names.push_back( *it );
    }
    v2_names.push_back('\0');
}

Вопрос: это самый эффективный способскопировать элементы из v1_name в v2_names?
Основной вопрос: Как перебрать v2_names и напечатать названия стран, содержащиеся в v2_names

Ответы [ 4 ]

2 голосов
/ 16 сентября 2011

Используйте простое соединение, прибыль!

#include <boost/algorithm/string/join.hpp>
#include <vector>
#include <iostream>

int main(int, char **)
{
    vector<string> v1_names = boost::assign::list_of("Antigua and Barbuda")( "Brasil")( "Papua New Guinea")( "Togo");

    std::string joined = boost::algorithm::join(v1_names, "\0");
}
1 голос
/ 16 сентября 2011

Для оценки хранилища вам, вероятно, следует измерить строки, а не полагаться на жестко запрограммированную константу 20. Например:

size_t total = 0;
for (std::vector<std::string>::iterator it = v1_names.begin(); it != v1_names.end(); ++it) {
    total += it->size() + 1;
}

Основная неэффективность в вашем цикле, вероятно, заключается в том, что вы берете дополнительную копию каждой строки по очереди: std::string val( v1_names[i] ); может вместо этого быть const std::string &val = v1_names[i];.

Чтобы добавить каждую строку, вы можете использовать функцию insert:

v2_names.insert(v2_names.end(), val.begin(), val.end());
v2_names.push_back(0);

Это не обязательно самый эффективный вариант, поскольку в векторе есть определенная избыточная проверка доступного пространства, но это не должно быть слишком плохо и просто. Альтернативой может быть размер v2_names в начале, а не резервирование места, а затем копировать данные (с std::copy), а не добавлять их. Но любой из них может быть быстрее, и это не должно иметь большого значения.

По основному вопросу, если все, что у вас есть, это v2_names, и вы хотите напечатать строки, вы можете сделать что-то вроде этого:

const char *p = &v2_names.front();
while (p <= &v2_names.back()) {
    std::cout << p << "\n";
    p += strlen(p) + 1;
}

Если у вас также есть name_len:

size_t offset = 0;
for (std::vector<int>::iterator it = name_len.begin(); it != name_len.end(); ++it) {
    std::cout << &v2_names[offset] << "\n";
    offset += *it + 1;
}

Помните, что тип name_len технически неверен - не гарантируется, что вы можете хранить длину строки в int. Тем не менее, даже если int меньше size_t в конкретной реализации, такие большие строки все равно будут довольно редкими.

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

Если вы хотите объединить все строки, вы можете просто использовать один проход и рассчитывать на амортизированные вставки O (1):

name_len.reserve(v1_names.size());

// v2_names.reserve( ??? ); // only if you have a good heuristic or
                            // if you can determine this efficiently

for (auto it = v1_names.cbegin(); it != v1_names.cend(); ++it)
{
  name_len.push_back(it->size());
  v2_names.insert(v2_names.end(), it->c_str(), it->c_str() + it->size() + 1);
}

Вы можете предварительно вычислить общую длинуперед этим выполните другой цикл и вызовите reserve, если считаете, что это поможет.Это зависит от того, насколько хорошо вы знаете струны.Но, возможно, нет никакого смысла беспокоиться, так как в конечном итоге вставки будут O (1).

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

Лучший способ вычислить требуемое хранилище - это суммировать длину каждой строки в v1_names.

Для вашего второго вопроса вместо использования цикла for вы можете просто использовать iterator, iterator метод добавления вектора с begin и end в строке.

Третий вопрос: просто не делай этого. Вместо этого перебирайте строки v1_names. Единственная причина, по которой когда-либо может создать такую ​​вещь, как v2_names, состоит в том, чтобы передать ее в унаследованный API C, и тогда вам не нужно беспокоиться об ее повторении.

...