Удалить любой контейнер с помощью шаблонов

У меня много кода, где я удаляю векторные контейнеры, в которых есть указатели, то есть сначала я должен удалить все указатели, а затем очистить контейнер. Каждый раз, когда я перебираю и удаляю указатели вручную (мне известны stl:: алгоритмы for_each). Чтобы обойти весь этот код, я создал шаблон для удаления всех векторных контейнеров, имеющих указатель. Все идет нормально.

Теперь у меня есть еще несколько типов контейнеров, включая карты, параллельные контейнеры и т. Д., И все они имеют одинаковую функциональность в конце процесса удаления. DeleteContainer(std::vector<T*>& VecIn) Функция, которая у меня есть, может работать только с векторами, как указано выше. Есть ли способ сделать его достаточно универсальным для работы со всеми контейнерами?

РЕДАКТИРОВАТЬ: Спасибо за все ответы, я хотел бы выбрать более одного. Любой, кто сталкивается с этим вопросом, прочитает все ответы, а не только выбранный, поскольку все они предоставляют отличную информацию.

7 ответов

Решение

У вас уже есть действительный ответ, но просто для того, чтобы предоставить альтернативу, я думаю, вам следует рассмотреть возможность использования Boost Pointer Container и позволить ему управлять памятью:

Поэтому эта библиотека предоставляет стандартные контейнеры, предназначенные для хранения выделенных в куче или клонированных объектов (или в случае карты сопоставленный объект должен быть выделенным в куче или клонированным объектом). Для каждого из стандартных контейнеров существует эквивалентный контейнер-указатель, который принимает собственность на объекты безопасным образом.

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

http://www.boost.org/doc/libs/1_38_0/libs/ptr_container/doc/reference.html

{
    boost::ptr_vector<int>   data;

    data.push_back(new int(2));
    data.push_back(new int(2));
    data.push_back(new int(2));
}
// container deleted and all pointers correctly destroyed.

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

template <typename Iter>  
void delete_pointers(Iter begin, Iter end)
{
    for (; begin != end; ++begin) delete *begin;
}

Использование:

std::vector<Foo*> v;

// Initialize Foo objects

delete_pointers(v.rbegin(), v.rend());

я использую rbegin а также rend вместо begin а также end потому что иногда люди хотят, чтобы объекты были удалены в обратном порядке их создания.

Вы также можете сделать

void destroyFoo(Foo* x) { delete x; }

std::for_each(v.rbegin(), v.rend(), &destroyFoo);

или используйте лямбды C++0x.

Вы можете просто использовать boost::shared_ptr<T> поставленный T* и не будет причины DeleteContainer, Но если вы не хотите делать это, вы можете сделать что-то вроде этого

template<class T>
void DeleteContainer(typename T::iterator begin, typename T::iterator end)
{
 for(;begin!=end;++begin)
  delete *begin;
}

тогда вы можете просто вызвать его для любого контейнера stl, который вы хотите следующим образом:

std::some_container<int*> s;
DeleteContainer<std::some_container<int*> > (s.begin(), s.end());

Как предположил Томек, у нас может быть подобное решение для удаления. Структура была бы лучше, чем свободная функция.

struct Delete
{
   public:
      template<typename T>
      void operator()(const T* ptr) const
      {
          delete ptr;
      }
      void operator()(const char* ptr) const
      {
          delete[] ptr;

     }
};

for_each (some_container.begin (), some_container.end (), Delete ());

Мой взгляд на это будет:

template<class T>
void Destroy(T *p)
{
  delete p;
}

template<template<typename, typename> class C, typename T1, typename T2>
void Destroy(C<T1 *, T2> &c)
{                                                        
  std::for_each(c.begin(), c.end(), Destroy<T1>);
}

Проверено на g++ 4.4.4 с вектором, deque и списком. Вам могут понадобиться дополнительные перегрузки void Destroy (C & c) для других контейнеров и / или других реализаций STL.

Альтернатива - отказаться от полного удаления и использовать сборщик мусора:). Вы можете попробовать сборщик Boehm-Reiser-Detlefs, он является стандартным для Linux (libgc) и сейчас используется во многих сложных программах (таких как: НКА). Это также хорошая идея отказаться от RAII: это была хорошая идея в то время, но она не так хорошо работает на практике. Многие ресурсы создаются и уничтожаются независимо друг от друга с их представлением.

Другие вопросы по тегам