Первое решение:
std::vector *vec = new std::vector;
assert(vec != NULL);
// ...
delete vec;
std::vector v;
//...
vec.clear();
vec.swap(std::vector(vec));
Что-то вроде приема второго решения---, что "правильный" путь состоит в том, чтобы сделать это?
Я знаю, что деструктор назовут, после того как это от стека, мне было любопытно на предмет других методов.
Самый простой и надежный способ освободить вектор - объявить его в стеке и просто ничего не делать.
void Foo() {
std::vector<int> v;
...
}
C ++ гарантирует, что деструктор v
будет вызываться при выполнении метода. Деструктор std :: vector
гарантирует, что вся выделенная им память будет освобождена. Пока тип T
для vector
имеет правильную семантику освобождения C ++, все будет хорошо.
Самый простой способ освободить всю память в векторе без разрушения самого векторного объекта - это
vec = std::vector<int>();
. Второй вариант будет иметь такой же эффект, но он перескакивает через большее количество обручей на способ. Уловка «копировать и переставлять» освобождает любую дополнительную емкость в векторе и может быть полезна, если он содержит некоторые данные, которые вы хотите сохранить. Если данных нет, то в копировании или подкачке нет необходимости.
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();
Удаление освобождает память, затем память освобождается для следующего объекта, но вектор ушел.
Второй прием освобождает лишнюю память, но оставляет вектор нетронутым, но пустым.
В случае, если вектор действительно должен быть в куче, не забывайте о:
std::auto_ptr<std::vector<int> > vec(new std::vector<int>);
особенно полезно с кодом вроде:
std::auto_ptr<std::vector<int> > vec(vectorFactoryFunction());
Если вы просто позволите вектору выйти за пределы области видимости, он очистится соответствующим образом без каких-либо дополнительных действий. Если вектор является переменной-членом класса, и вы хотите, чтобы он освободил свое содержимое до того, как его владелец будет уничтожен, просто вызовите vec.clear ().
Если вы хотите сохранить вектор, но освободить память, содержащую его содержимое, то vec.swap (std :: vector
сделает это. Нет необходимости копировать-конструировать временное в оригинал, если vec не содержит элементы, которые вы хотите сохранить, и вы просто хотите уменьшить выделенную память до чего-то близкого к текущему размеру ().
Я не уверен, почему в вашем втором примере для временного конструктора используется конструктор копирования, а не конструктор по умолчанию. Это сэкономит вам строку кода .clear ()
.
Вы можете сделать это универсальным для любого объекта, даже если это не контейнер. Я предполагаю, что std :: swap специализируется на вызове vector :: swap.
template<typename T>
void ResetToDefault(T & value)
{
std::swap(T(), value);
}
std::vector<int> vec;
//...
ResetToDefault(vec);
Хотя оба варианта, похоже, работают, я не вижу причин не вызывать delete для указателя. Вектор должен иметь вызываемый деструктор, который будет обрабатывать все остальное.
Не используйте функции выделения памяти, если это действительно не нужно. Если вашему классу нужен вектор, всегда просто добавляйте член std::vector напрямую. Здесь нет необходимости в выделении памяти.
В случаях, когда вам нужен динамический вектор, выделение и удаление его, как в вашем первом примере, является 100% правильным.
Во втором примере вызов std::swap, строго говоря, не нужен, потому что метод clear очистит вектор, сделав его пустым. Одна из возможных проблем заключается в том, что нет гарантии, что вектор действительно освободит память, вернув ее операционной системе (или времени выполнения). Вектор может сохранить выделенную память на случай, если вы заполните вектор сразу после его очистки. Вызов std::swap может быть трюком, чтобы "заставить" вектор освободить свои внутренние данные, но нет никакой гарантии, что это действительно произойдет.
Это некорректное сравнение, потому что примеры имеют дело с разными типами объектов: динамическая длительность и локальная длительность. Вы можете вызвать деструктор ИЛИ использовать трюк swap (он же shrink_to_fit) с любым из них. правильный способ зависит от того, нужно ли вам, чтобы векторный объект сохранялся или нет.
Например, вам может понадобиться, чтобы он сохранялся, если есть ссылки или указатели на него, которые должны оставаться действительными, и в этом случае уменьшение - единственный способ, независимо от того, как он был выделен.
Я предполагаю, что у вас есть вектор, который временно содержит большой объем данных. Как только вектор будет очищен, он все равно займет всю эту память. Вы хотите освободить эту память после того, как закончите с ней, но функция / объект, с которыми вы работаете, еще не закончили.
Решения в порядке убывания желательности:
Единственная техническая разница между заменой мест и удалением заключается в том, что сам базовый вектор не уничтожается. Это небольшие накладные расходы, о которых не стоит беспокоиться (если вы в конечном итоге уничтожите вектор)
Более серьезное соображение заключается в том, что упрощает написание правильного кода, и я считаю, что подкачка лучше удаления там, но хуже затем перемещаем вектор в другое место.