2013-05-02 4 views
3

Из того, что я читал, std::vector - это подходящая структура для взаимодействия с c-функцией, требующей массива массива смежных массивов. Однако мне было интересно, как я могу определить размер массива в некоторых случаях.Правильный способ установки размера std :: vector

Я написал небольшую пробную программу, чтобы проиллюстрировать, что я имею в виду.

int main(int argc, char *argv[]) 
{ 
    std::vector<unsigned char>v; 
    unsigned char p[1024]; 

    sprintf((char*)&p[0], "%10d", 10); 
    cout << "Size: " << v.size() << " Length: " << v.capacity() << endl; 
    v.reserve(30); 
    cout << "Size: " << v.size() << " Length: " << v.capacity() << endl; 
    memcpy(&v[0], &p[0], 20); 
    cout << "Size: " << v.size() << " Length: " << v.capacity() << endl; 
    v.reserve(50); 
    cout << "Size: " << v.size() << " Length: " << v.capacity() << endl; 
    v.reserve(0); 
    cout << "Size: " << v.size() << " Length: " << v.capacity() << endl; 
    v.resize(20); 
    cout << "Size: " << v.size() << " Length: " << v.capacity() << endl; 
    v.resize(0); 
    cout << "Size: " << v.size() << " Length: " << v.capacity() << endl; 

    return 0; 
} 

Выход (не очень удивительно):

Size: 0 Length: 0 
Size: 0 Length: 30 
Size: 0 Length: 30 
Size: 0 Length: 50 
Size: 0 Length: 50 
Size: 20 Length: 50 
Size: 0 Length: 50 

Причина, почему я сделал это, потому что я оставляю за собой буфер определенного размера, а затем передать эту память в гнездо через recv() , Поскольку я должен передать память как указатель, нет никакого способа, чтобы размер вектора корректировался в соответствии с тем, что возвращает recv. Теперь, когда полученное количество байтов меньше, чем буфер, я бы подумал, что могу как-то отрегулировать размер вектора, поэтому, когда я его передаю, вызывающий может сделать v.size(), а количество элементов, возвращаемых Получать.

Когда я посмотрел данные из приведенного выше примера, при использовании resize() размер буфера отрегулирован правильно, но данные ушли. Так что мне действительно нужно копировать память по отдельности в новый вектор, чтобы получить правильный размер? Это звучит как действительно ненужные накладные расходы для меня. Или есть способ сообщить вектору, сколько элементов в настоящее время предполагается удерживать?

ответ

5

Вы делаете что-то не в порядке.

  1. resize до максимального размера, который вы хотите, чтобы ваш буфер принимался.
  2. Сохраните данные (которые должны быть меньше размера вектора).
  3. resize Настоящий размер данных.

Ваша проблема «исчезновения данных» заключается в том, что, когда вы копируете данные в первый раз, ваш вектор имеет размер не только размера (т. Е. Предварительно зарезервированную память, фактически не используя ее для хранения данных). Когда вы снова reserve, размер по-прежнему равен 0, поэтому вектор может оптимизировать копию данных, так как он знает, что он должен содержать только первые size() элементов (то есть 0).

Другими словами:

  • capacity() = сколько данных вы можете поместить в вектор, не вызывая перераспределение.
  • size() = сколько данных вы действительно используете (и вектор будет держать только что данные по перераспределении)

Более того, доступ к элементам вектора мимо его текущего size() является Неопределенное поведение (это может похоже, работают со встроенными типами, но думают о том, что произойдет с неинициализированными объектами ...). Не делай этого.

+0

Спасибо, это был действительно правильный ответ, и я проверил его с помощью моей тестовой программы в отладчике. Теперь я также понимаю, почему. :) Это также соответствует моей модели реализации, поскольку я не использую конструктор в начале, но хочу установить размер вручную. – Devolus

3

recv прямо в буфер, то вдоль линий:

std::vector< unsigned char > buffer(1024); 
buffer.resize(recv(&buffer[0], buffer.size())); 

В зависимости от того, если RECV может возвращать коды ошибок, возможно, придется проверить перед изменением размера.

+0

И это будет гарантировать, что данные не будут потеряны во время изменения размера? Потому что это то, что я смоделировал с memcpy в коротком образце. Когда я вызываю прием, ОС поместит данные из сокета в буфер, и я знаю, что вектор не может это сделать. Вот почему мне нужно настроить размер() после этого, поэтому вектор знает, сколько элементов он держит, но он, очевидно, не должен потерять данные в процессе, что, по-видимому, так и происходит, потому что векторная реализация касается только известных элементов. – Devolus

+0

@Devolus: вектор инициализирован для хранения 1024 элементов, поэтому он уже знает, что существует 1024 допустимых элемента (на которых 'recv' пишет); 'resize' просто скорректирует количество элементов на фактически используемые элементы и (возможно) обрезает используемую память. –

+1

@MatteoItalia 'resize' не может перераспределять, если это не нужно, поэтому он не может сделать буфер меньше. В C++ 11 существует функция 'std :: vector <> :: shrink_to_fit', которая может использоваться для уменьшения используемой памяти или вы можете сделать что-то вроде' std :: vector (v.begin(), v.end()) .swap (v); '. –

0

v.reserve(n) для установки: n.

m = recv(s,&v[0],n,0) 

v.resize(m) установить вектор размера к тому, что RECV получил.

+4

Если вы не задали размер раньше, вы никогда не увидите, что такое 'recv'. (Также, конечно, у вас есть неопределенное поведение.) –

0

Когда вы копируете что-то в ячейку памяти, начиная с первого байта буфера вектора, тогда вектор не знает об этом и не будет обновлять свой внутренний счетчик размера. Используйте методы assign() или insert() для копирования буфера в вектор.

reserve() не уменьшает ранее сохраненную емкость. Вот почему в последней строке вы все равно видите 50, но вы уменьшили ее до 20.

Смежные вопросы