Очистка списка STL / вектора указателей - PullRequest
49 голосов
/ 21 ноября 2008

Какой кратчайший кусок C ++ вы можете придумать для безопасной очистки вектора или списка указателей? (при условии, что вам нужно вызвать delete на указателях?)

list<Foo*> foo_list;

Я бы предпочел не использовать Boost или оборачивать мои указатели умными указателями.

Ответы [ 15 ]

53 голосов
/ 21 ноября 2008

Для std::list<T*> используйте:

while(!foo.empty()) delete foo.front(), foo.pop_front();

Для std::vector<T*> используйте:

while(!bar.empty()) delete bar.back(), bar.pop_back();

Не уверен, почему я взял front вместо back для std::list выше. Я думаю, это чувство, что это быстрее. Но на самом деле оба являются постоянным временем :). В любом случае, оберните это в функцию и получайте удовольствие:

template<typename Container>
void delete_them(Container& c) { while(!c.empty()) delete c.back(), c.pop_back(); }
52 голосов
/ 21 ноября 2008

Так как мы бросаем вызов здесь ... "Самый короткий кусок C ++"

static bool deleteAll( Foo * theElement ) { delete theElement; return true; }

foo_list . remove_if ( deleteAll );

Я думаю, мы можем доверять людям, которые придумали STL, для разработки эффективных алгоритмов. Зачем изобретать велосипед?

29 голосов
/ 21 ноября 2008
for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); ++it)
{
    delete *it;
} 
foo_list.clear();
16 голосов
/ 13 февраля 2014

Если вы разрешите C ++ 11, вы можете сделать очень короткую версию ответа Дугласа Лидера:

for(auto &it:foo_list) delete it; foo_list.clear();
13 голосов
/ 21 ноября 2008

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

Я знаю, что вы сказали, что вам не нравится повышение, но, пожалуйста, рассмотрите контейнеры указателя повышения .

9 голосов
/ 21 ноября 2008
template< typename T >
struct delete_ptr : public std::unary_function<T,bool>
{
   bool operator()(T*pT) const { delete pT; return true; }
};

std::for_each(foo_list.begin(), foo_list.end(), delete_ptr<Foo>());
6 голосов
/ 21 ноября 2008

Я не уверен, что подход функтора выигрывает здесь для краткости.

for( list<Foo*>::iterator i = foo_list.begin(); i != foo_list.end(); ++i )
    delete *i;

Я обычно советую против этого, хотя. Как правило, упаковка указателей в интеллектуальные указатели или использование специализированного контейнера указателей будет более надежной. Существует множество способов удаления элементов из списка (различные варианты erase, clear, уничтожение списка, назначение через список итератором и т. Д.). Можете ли вы гарантировать, что поймаете их всех?

5 голосов
/ 30 апреля 2012

Следующий хак удаляет указатели, когда ваш список выходит из области видимости с помощью RAII или если вы вызываете list :: clear ().

template <typename T>
class Deleter {
public:
  Deleter(T* pointer) : pointer_(pointer) { }
  Deleter(const Deleter& deleter) {
    Deleter* d = const_cast<Deleter*>(&deleter);
    pointer_ = d->pointer_;
    d->pointer_ = 0;
  }
  ~Deleter() { delete pointer_; }
  T* pointer_;
};

Пример:

std::list<Deleter<Foo> > foo_list;
foo_list.push_back(new Foo());
foo_list.clear();
4 голосов
/ 10 апреля 2014
for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); it++)
{
    delete *it;
} 
foo_list.clear();

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

std :: list <> :: clear является линейным по сложности; он удаляет и уничтожает один элемент за раз в цикле.

Принимая во внимание вышесказанное, самое простое на мой взгляд решение:

while(!foo_list.empty())
{
    delete foo_list.front();
    foo_list.pop_front();
}
4 голосов
/ 20 апреля 2010

На самом деле, я считаю, что библиотека STD предоставляет прямой метод управления памятью в виде класса-распределителя

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

Я / думаю / это тот тип вещей, для которых он предназначен.

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