Вопрос:

std :: vector :: resize () против std :: vector :: reserve ()

c++ stl vector

47002 просмотра

6 ответа

29659 Репутация автора

Существует поток в разделе комментариев в этой записи об использовании 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 правильным или неправильным?

Автор: Mr.C64 Источник Размещён: 23.10.2012 11:19

Ответы (6)


2 плюса

423028 Репутация автора

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

Автор: Konrad Rudolph Размещён: 23.10.2012 11:22

99 плюса

27403 Репутация автора

Решение

Есть два разных способа по причине:

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

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

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

Автор: CashCow Размещён: 23.10.2012 11:24

22 плюса

8411 Репутация автора

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

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

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

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

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

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

РЕДАКТИРОВАТЬ 2: Редактировать вопрос объявления: если у вас есть начальная оценка, чем резерв (), которая оценивает и если этого оказывается недостаточно, просто дайте вектору сделать свое дело.

Автор: lucasg Размещён: 23.10.2012 11:26

11 плюса

133469 Репутация автора

Это зависит от того, что вы хотите сделать. 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;
    }
}

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

Автор: James Kanze Размещён: 23.10.2012 11:28

1 плюс

3306 Репутация автора

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

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

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

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

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

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

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

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

Автор: odinthenerd Размещён: 23.10.2012 11:33

2 плюса

811 Репутация автора

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

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

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

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

Автор: Dula Размещён: 07.07.2015 09:32
32x32