СТД::вектор::изменение размера() и СТД::вектор::резерв()


в разделе комментариев в этом посте есть тема об использовании std::vector::reserve() и 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, или это неправильно?

6 58

6 ответов:

есть два разных метода по какой-то причине:

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

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

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

ответ здесь Января Hudec: выбор между vector:: resize() и vector:: reserve ()

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

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

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

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

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

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

это зависит от того, что вы хотите сделать. reserve тут не добавить любые элементы для vector; меняется только capacity(), которым гарантирует, что добавлять элементы не будут перераспределять (например, недействительным итераторы). resize добавляет элементы немедленно. Если вы хотите чтобы добавить элементы позже (insert(),push_back()), используйте reserve. Если вы хотите получить доступ к элементам позже (используя [] или at()), используйте resize. Так ты 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;
    }
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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