Выбор между vector :: resize () и vector :: reserve () - PullRequest
136 голосов
/ 13 сентября 2011

Я предварительно выделяю часть памяти для моей переменной vector. Ниже код минимальная часть

class A {
  vector<string> t_Names;
public:
  A () : t_Names(1000) {}
};

Теперь в какой-то момент времени, если t_Names.size() равно 1000. Я собираюсь увеличить размер на 100. Затем, если оно достигнет 1100, снова увеличьте на 100 и т. Д.

Мой вопрос: что выбрать между vector::resize() и vector::reserve(). Есть ли лучший выбор в этом сценарии?

Редактировать : У меня есть точная оценка для t_Names. Я оцениваю это примерно от 700 до 800. Однако в определенных (редко) ситуациях он может вырасти более чем на 1000.

Ответы [ 4 ]

232 голосов
/ 13 сентября 2011

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

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

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

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

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

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

26 голосов
/ 13 сентября 2011

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

std::vector<int> v1;
v1.resize(1000); //allocation + instance creation
cout <<(v1.size() == 1000)<< endl;   //prints 1
cout <<(v1.capacity()==1000)<< endl; //prints 1

std::vector<int> v2;
v2.reserve(1000); //only allocation
cout <<(v2.size() == 1000)<< endl;   //prints 0
cout <<(v2.capacity()==1000)<< endl; //prints 1

Вывод ( онлайн-демонстрация ):

1
1
0
1

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

2 голосов
/ 13 сентября 2011

резервировать, если вы не хотите, чтобы объекты инициализировались при резервировании. Кроме того, при изменении размера вы можете предпочесть логически дифференцировать и отслеживать его количество в зависимости от его количества использования. поэтому в интерфейсе есть поведенческая разница - вектор будет представлять то же количество элементов при резервировании, и будет на 100 элементов больше при изменении размера в вашем сценарии.

Есть ли лучший выбор в этом сценарии?

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

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

1 голос
/ 13 сентября 2011

Из вашего описания похоже, что вы хотите "зарезервировать" выделенное пространство для хранения вектора t_Names.

Обратите внимание, что resize инициализирует только что выделенный вектор, где reserve просто выделяет, но не создает. Следовательно, «резерв» намного быстрее , чем «изменение размера»

Вы можете обратиться к документации, касающейся разницы изменения размера и резерва

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...