Подтвердить что ты не робот

Очистка списка/вектора STL указателей

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

list<Foo*> foo_list;

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

4b9b3361

Ответ 1

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

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

foo_list . remove_if ( deleteAll );

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

Ответ 2

Для 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(); }

Ответ 3

for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); ++it)
{
    delete *it;
} 
foo_list.clear();

Ответ 4

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

for(auto &it:foo_list) delete it; foo_list.clear();

Ответ 5

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

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

Ответ 6

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>());

Ответ 7

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

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

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

Ответ 8

Следующий хак удаляет указатели, когда ваш список выходит из области действия с использованием 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();

Ответ 9

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

for (list<Foo*>::iterator i = foo_list.begin(), e = foo_list.end(); i != e; )
{
    list<Foo*>::iterator tmp(i++);
    delete *tmp;
    foo_list.erase(tmp);
}

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

Ответ 10

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();
}

Ответ 11

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

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

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

Ответ 12

Так как С++ 11:

std::vector<Type*> v;
...
std::for_each(v.begin(), v.end(), std::default_delete<Type>());

Или, если вы пишете шаблонный код и хотите не указывать конкретный тип:

std::for_each(v.begin(), v.end(),
    std::default_delete<std::remove_pointer<decltype(v)::value_type>::type>());

Которая (поскольку С++ 14) может быть сокращена как:

std::for_each(v.begin(), v.end(),
    std::default_delete<std::remove_pointer_t<decltype(v)::value_type>>());

Ответ 13

void remove(Foo* foo) { delete foo; }
....
for_each( foo_list.begin(), foo_list.end(), remove );

Ответ 14

for (list<Foo*>::const_iterator i = foo_list.begin(), e = foo_list.end(); i != e; ++i)
    delete *i;
foo_list.clear();