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

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

 john23 окт. 2012 г., 13:22
Я согласен с вами, но, без сомнения, Лучиан скоро придет и объяснит.
 Default23 окт. 2012 г., 13:27
Я пометил это как "слишком локализованный", так как @LuchianGrigore редко ошибается
 Mr.C6423 окт. 2012 г., 13:23
@LuchianGrigore: Это хорошо. Каждый может ошибаться :)
 Luchian Grigore23 окт. 2012 г., 13:22
Объяснение может быть так просто, как «я был неправ»: D
 Luchian Grigore23 окт. 2012 г., 13:27
@Default читал «редко неправильно» как «быстро исправляя свои ошибки» :)

Ответы на вопрос(6)

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

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

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

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

 John Gordon27 окт. 2016 г., 17:26
Изменение размераникогда освобождает память Когда размер становится меньше, будут вызываться деструкторы, но память сохраняется (емкость не меняется).

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

Решение Вопроса

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

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

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

 hailinzeng02 июн. 2015 г., 17:58
так, для пустого вектора, то есть vec, после того, как резервный vec [1] закончится с ошибкой сегмента.
 Post Self20 апр. 2017 г., 22:25
Будетstd::vector::reserve предотвратить случайное копирование полного массива наpush_back?
 Mr.C6423 окт. 2012 г., 13:35
Это было и мое понимание.
 CashCow02 июн. 2015 г., 17:59
vec [1] будет неопределенным поведением.

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

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

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

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

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

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

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

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

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

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

Ян Худек : Выбор между vector :: resize () и vector :: reserve ()

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

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

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

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

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

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

Ваш ответ на вопрос