О разных способах заполнения вектора - PullRequest
5 голосов
/ 11 января 2011

Я могу придумать три способа заполнения std::vector

Предположим, что у нас есть

vector<int> v(100, 0);

Тогда я хочу, чтобы оно сохранилось (1, 1, 1).Мы можем сделать:

v.clear();
v.resize(3, 1);

Или

v = vector<int>(3, 1);

И я изучил другой подход:

vector<int>(3, 1).swap(v); 

Первый вопрос: какой из них лучший?

Второй вопрос: предположим, что v был объявлен вне основной функции.Согласно этому ответу , память будет выделена в сегменте данных.Если я буду использовать второй или третий подход, будет ли выделяться память в стеке?

Ответы [ 5 ]

9 голосов
/ 11 января 2011

Как насчет использования члена вектора, который существует для этой задачи?

std::vector<int> v(100);
v.assign(3, 1); // this is what you should do.
3 голосов
/ 11 января 2011

Итак, вот различия, и я позволю вам решить, что лучше для вашей ситуации.

v.clear();
v.resize(3, 1);

В этом случае мы пометили вектор как очищенный.Он по-прежнему содержит все, что было выделено для хранения 100 элементов (что может быть больше, чем пространство, необходимое для 100 элементов).Затем мы добавили 3 элемента со значением 1. Все, что они сделали, это увеличили счетчик размера и сбросили 3 значения, основная память все еще остается той же самой.создается дополнительный временный вектор, и вместо периодических мест, где счетчик равен 0, а затем 3 с некоторыми значениями, он просто копирует размер счетчика, а затем выполняет операцию, аналогичную memcpy, для копирования трех элементов.Размер основной памяти, выделенной для v, все еще достаточен для хранения 100 целых чисел.

vector<int>(3, 1).swap(v); 

Этот показатель существенно отличается.В этом случае мы создаем временный вектор, который содержит 3 элемента, все из которых инициализированы в 1. Теоретически у него все еще может быть достаточно памяти, зарезервированной для 100 элементов, но есть вероятность, что он имеет гораздо меньше.Затем мы меняем этот вектор своим собственным и позволяем временному уничтожаться.Это дает дополнительное преимущество очистки любой дополнительной памяти, выделенной нашим старым вектором, который не был во временном.Это работает так, что два вектора (наш v и временный) меняют местами не только счетчики и значения, они также меняют указатели буфера.

Это единственный способ уменьшить вектор.

2 голосов
/ 11 января 2011

Чтобы ответить на второй вопрос первым: vector всегда будет динамически выделять память для объектов, которые в нем содержатся, поэтому он окажется в куче.

Что касается того, какой метод переназначения лучше, я бы сказал, что ваш первый или второй метод прояснит ваше намерение, и это самый важный атрибут.

1 голос
/ 11 января 2011

Одна проблема, не упомянутая в предыдущих постах, важна при выборе среди этих альтернатив. А именно, исключение безопасности. vector<int>(3, 1).swap(v); имеет строгую исключительную гарантию безопасности. Форма v = vector<int>(3, 1); также может предложить такую ​​гарантию, если присвоение осуществляется в условиях обмена. Первый вариант небезопасен: v.clear(); v.resize(3, 1);

1 голос
/ 11 января 2011

Замена будет эффективно уменьшать вектор до 3 элементов. Другие, скорее всего, не будут.

vector<int> v(100);
v.assign(3, 1);
assert(v.size() == 3);
assert(v.capacity() != 3);

v = vector<int>(3, 1);
// Now, v.capacity() is likely not to be 3.

vector<int>(3, 1).swap(v);
assert(v.capacity() == 3);

Другие подходы не изменят размер вектора внутренне. Он по-прежнему будет занимать 100 * sizeof (int) байтов в памяти, даже если элемент size () возвращает 3. Попробуйте отобразить v.capacity(), чтобы убедить себя.

...