Правильный способ задать размер std:: вектор


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

Я написал небольшой пример программы, чтобы проиллюстрировать, что я имею в виду.
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() и количество элементов, возвращаемых receive.

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

4 3

4 ответа:

Вы делаете вещи в неправильном порядке.

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

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

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

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

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

recv прямо в буфер, что-то вроде:

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

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

v.reserve(n) установить емкость в n.

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

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

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

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