«Правильный» способ освободить объект std :: vector - PullRequest
34 голосов
/ 16 июня 2010

Первое решение:

std::vector<int> *vec = new std::vector<int>;
assert(vec != NULL);
// ...
delete vec;

Альтернатива :

std::vector<int> v;
//...
vec.clear();
vec.swap(std::vector<int>(vec));

Второе решение немного хитрое - что за "правильный "способ сделать это?

Обновление:

Я знаю, что деструктор будет вызван, как только он выйдет из стека, мне было любопытно, другие методы.

Ответы [ 12 ]

36 голосов
/ 16 июня 2010

Самый простой и надежный способ освободить вектор - это объявить его в стеке и просто ничего не делать.

void Foo() {
  std::vector<int> v;
  ...
}

C ++ гарантирует, что деструктор v будет вызван при выполнении метода,Деструктор std::vector обеспечит освобождение любой выделенной памяти.Пока тип T vector<T> имеет правильную семантику освобождения C ++, все будет хорошо.

15 голосов
/ 16 июня 2010

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

vec = std::vector<int>();

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

13 голосов
/ 16 июня 2010
std::vector<int> vi;
/*push lots of stuff into the vector*/

// clean it up in C++03
// no need to clear() first
std::vector<int>().swap(vi);

// clean it up in C++0x
// not a one liner, but much more idiomatic
vi.clear();
vi.shrink_to_fit();
3 голосов
/ 09 февраля 2016

Я согласен с Майком Сеймуром, попробуйте это, тогда вы заметите, что последний работает нормально

1 голос
/ 16 июня 2010

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

Решения в порядке убывания желательности:

  1. Переработкакод, чтобы вектор, использующий код, находился в своем собственном блоке / функции / объекте, так что он будет уничтожен естественным образом
  2. Используйте трюк подкачки, так что вам не нужно беспокоиться о том, чтобы убедиться, что векторосвобождается при любых обстоятельствах.Его время жизни будет привязано к объекту / функции, в которой вы находитесь.
  3. new / delete вектор.Это освободит немного больше памяти, чем предыдущий метод, но также сложнее убедиться, что нет утечки памяти.

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

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

1 голос
/ 16 июня 2010

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

В тех случаях, когда вам нужен динамический вектор, его выделение и удаление, как в первом примере, выполняется на 100% правильно.

Во втором примеревызов std :: swap строго не нужен, поскольку метод clear очищает вектор, делая его пустым.Одна из возможных проблем заключается в том, что нет гарантии, что вектор действительно освободит память, вернув ее обратно операционной системе (или во время выполнения).Вектор может сохранить выделенную память на тот случай, если вы заполните вектор сразу после очистки.Вызов std :: swap может быть хитростью, чтобы заставить вектор освободить свои внутренние данные, но нет никакой гарантии, что это действительно произойдет.

0 голосов
/ 16 июня 2010

В случае, когда вектор действительно должен быть в куче, не забудьте:

std::auto_ptr<std::vector<int> > vec(new std::vector<int>);

особенно полезно с кодом вроде:

std::auto_ptr<std::vector<int> > vec(vectorFactoryFunction());
0 голосов
/ 16 июня 2010

Я не уверен, почему ваш второй пример использует конструктор копирования для временного, а не конструктор по умолчанию. Это сэкономит вам строку кода .clear().

Вы можете сделать это универсальным для любого объекта, даже если это не контейнер. Я предполагаю, что std :: swap специализирован для вызова vector :: swap.

template<typename T>
void ResetToDefault(T & value)
{
    std::swap(T(), value);
}

std::vector<int> vec;  
//...  
ResetToDefault(vec);
0 голосов
/ 16 июня 2010

Это недопустимое сравнение, потому что примеры имеют дело с различными типами объектов: динамическая длительность и локальная длительность. Вы можете вызвать деструктор ИЛИ использовать трюк подкачки (aka shrink_to_fit) с любым из них. Способ right зависит от того, нужен ли векторный объект для сохранения или нет.

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

0 голосов
/ 16 июня 2010

Если вы просто позволите вектору выйти из области видимости, он будет очищен соответствующим образом без дополнительной работы.Если вектор является переменной-членом класса, и вы хотите, чтобы он освободил свое содержимое до уничтожения его владельца, просто вызовите vec.clear ().

Если вы хотите сохранить вектор, но освободитьпамять, которая содержит его содержимое, тогда vec.swap(std::vector<int>()); сделает это.Нет необходимости копировать-создавать временные данные в оригинал, если только vec не содержит элементы, которые вы хотите сохранить, и вы просто хотите уменьшить выделенную память до значения, близкого к текущему размеру ().

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