Подтвердить что ты не робот

Std::vector:: resize() vs. std::vector:: reserve()

В разделе комментариев в этом сообщении есть поток, посвященный использованию std::vector::reserve() vs. std::vector::resize().

Вот исходный код:

void MyClass::my_method()
{
    my_member.reserve(n_dim);
    for(int k = 0 ; k < n_dim ; k++ )
         my_member[k] = k ;
}

Я считаю, что для записи элементов в vector, правильная вещь - вызвать std::vector::resize(), а не std::vector::reserve().

Фактически, следующий тестовый код "сбой" в отладочных сборках в VS2010 SP1:

#include <vector>

using namespace std;

int main()
{
    vector<int> v;
    v.reserve(10);
    v[5] = 2;

    return 0;
}

Я прав, или я ошибаюсь? И VS2010 SP1 прав, или это неправильно?

4b9b3361

Ответ 1

Существует два разных метода:

std::vector::reserve будет выделять память, но не будет изменять размер вашего вектора, который будет иметь логический размер так же, как и раньше.

std::vector::resize фактически изменит размер вашего вектора и заполнит любое пространство объектами в их состоянии по умолчанию. Если они являются ints, все они будут равны нулю.

После сохранения в вашем случае вам понадобится много push_backs для записи в элемент 5. Если вы не хотите этого делать, то в вашем случае вы должны изменить размер.

Ответ 2

Ответ здесь Ян Худек: Выбор между vector:: resize() и vector:: reserve()

Две функции выполняют совершенно разные вещи.

Метод resize() (и передающий аргумент конструктору эквивалентен этому) вставляет заданное число элементов в вектор (у него есть необязательный второй аргумент, чтобы указать их значение). Это повлияет на размер(), итерация будет проходить через все эти элементы, push_back будет вставляться после них, и вы можете напрямую обращаться к ним с помощью оператора [].

Метод reserve() только выделяет память, но оставляет ее неинициализированной. Это влияет только на capacity(), но size() не изменится. Для объектов нет значения, потому что ничего не добавляется к вектору. Если вы вставляете элементы, перераспределение не произойдет, потому что это было сделано заранее, но это единственный эффект.

Так что это зависит от того, что вы хотите. Если вам нужен массив из 1000 элементов по умолчанию, используйте resize(). Если вам нужен массив, в который вы ожидаете вставить 1000 элементов, и вы хотите избежать нескольких распределений, используйте reserve().

EDIT: комментарий Blastfurnace заставил меня снова прочитать вопрос и понять, что в вашем случае правильный ответ не предопределяется вручную. Просто продолжайте вставлять элементы в конце по мере необходимости. Вектор будет автоматически перераспределяться по мере необходимости и будет делать это более эффективно, чем упомянутый ручной способ. Единственный случай, когда имеет смысл reserve(), - это когда у вас есть достаточно точная оценка общего размера, который вам нужно будет легко получить заранее.

EDIT2: Редактирование вопроса: если у вас есть начальная оценка, чем reserve(), которая оценивается, и если этого оказалось недостаточно, просто дайте вектору сделать это.

Ответ 3

Это зависит от того, что вы хотите сделать. reserve не добавляет элементов к vector; он меняет только capacity(), который гарантирует, что добавляемые элементы не будут перераспределены (и, например, аннулировать итераторы). resize добавляет элементы немедленно. Если ты хочешь для добавления элементов позже (insert(), push_back()) используйте reserve. если ты хотите получить доступ к элементам позже (используя [] или at()), используйте resize. Так youre MyClass::my_method может быть:

void MyClass::my_method()
{
    my_member.clear();
    my_member.reserve( n_dim );
    for ( int k = 0; k < n_dim; ++ k ) {
        my_member.push_back( k );
    }
}

или

void MyClass::my_method()
{
    my_member.resize( n_dim );
    for ( int k = 0; k < n_dim; ++ k ) {
        my_member[k] = k;
    }
}

Какой вы выбрали, это вопрос вкуса, но код, который вы цитируете, явно неверно.

Ответ 4

Да, ты прав, Лучиан просто сделал опечатку и, вероятно, слишком лишен кофе, чтобы осознать свою ошибку.

Ответ 5

Вероятно, должно быть обсуждение о том, когда вызываются оба метода с числом, которое МЕНЬШЕ, чем текущий размер вектора.

Вызов reserve() с номером, меньшим, чем емкость, не повлияет на размер или емкость.

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

Подводя итог resize(), высвободит память, тогда как reserve() не будет.

Ответ 6

изменение размера фактически меняет количество элементов в векторе, новые элементы по умолчанию построены, если изменение размера приводит к росту вектора.

vector<int> v;
v.resize(10);
auto size = v.size();

в этом случае размер равен 10.

резерв, с другой стороны, требует только того, чтобы внутренний буфер был увеличен до указанного размера, но не меняет "размер" массива, изменяется только его размер буфера.

vector<int> v;
v.reserve(10);
auto size = v.size();

в этом случае размер по-прежнему равен 0.

Итак, чтобы ответить на ваш вопрос, да, вы правы, даже если вы зарезервируете достаточно места, вы по-прежнему обращаетесь к неинициализированной памяти с помощью оператора индекса. С int это не так плохо, но в случае вектора классов вы будете обращаться к объектам, которые не были построены.

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