Удалить любой контейнер с помощью шаблонов - PullRequest
9 голосов
/ 18 декабря 2010

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

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

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

Ответы [ 7 ]

7 голосов
/ 18 декабря 2010

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

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

4 голосов
/ 18 декабря 2010

Я помогу многим людям и буду использовать 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 lambdas.

4 голосов
/ 18 декабря 2010

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

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.
3 голосов
/ 18 декабря 2010

Вы можете просто использовать 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());
1 голос
/ 19 декабря 2010

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

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

0 голосов
/ 19 декабря 2010

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

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.

0 голосов
/ 18 декабря 2010

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

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