Как я использовал бы for_each для удаления каждого значения в карте STL?

Предположим, что у меня есть карта STL, где значения являются указателями, и я хочу удалить их всех. Как был бы я представлять следующий код, но использование станд.:: for_each? Я счастлив за решения использовать Повышение.

for( stdext::hash_map<int, Foo *>::iterator ir = myMap.begin();
     ir != myMap.end();
     ++ir )
{
  delete ir->second; // delete all the (Foo *) values.
}

(Я нашел Повышение checked_delete, но я не уверен, как применить это к pair<int, Foo *> то, что итератор представляет).

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

Примечание: Я впоследствии нашел и перечислил короткий ответ ниже..., но код довольно ужасен, таким образом, я принял более нормальный ответ GMAN.

7
задан Brian Tompsett - 汤莱恩 6 July 2015 в 14:00
поделиться

4 ответа

Вы должны создать функциональный объект:

struct second_deleter
{
    template <typename T>
    void operator()(const T& pX) const
    {
        delete pX.second;
    }
};

std::for_each(myMap.begin(), myMap.end(), second_deleter());

Если вы используете ускорение, вы также можете использовать библиотеку лямбда:

namespace bl = boost::lambda;
std::for_each(myMap.begin(), myMap.end(), second_deleter(),
                bl::bind(bl::delete_ptr(), 
                bl::bind(std::select2nd<myMap::value_type>(), _1));

Но вы можете попробовать библиотеку контейнеров указателей , которая делает это автоматически .

Обратите внимание, что вы используете не карту, а hash_map . Я рекомендую вам переключиться на boost unordered_map , который более актуален. Однако, похоже, не существует ptr_unordered_map .

В целях безопасности закройте это дело. Например:

template <typename T, typename Deleter>
struct wrapped_container
{
    typedef T container_type;
    typedef Deleter deleter_type;

    wrapped_container(const T& pContainer) :
    container(pContainer)
    {}

    ~wrapped_container(void)
    {
        std::for_each(container.begin(), container.end(), deleter_type());
    }

    T container;
};

И используйте это как:

typedef wrapped_container<
            boost::unordered_map<int, Foo*>, second_deleter> my_container;

my_container.container./* ... */

Это гарантирует, что несмотря ни на что, ваш контейнер будет повторен с помощью удаления. (Например, для исключений.)

Сравните:

std::vector<int*> v;
v.push_back(new int);

throw "leaks!"; // nothing in vector is deleted

wrapped_container<std::vector<int*> > v;
v.container.push_back(new int);

throw "no leaks!"; // wrapped_container destructs, deletes elements
14
ответ дан 6 December 2019 в 11:48
поделиться

Вы пробовали использовать BOOST_FOREACH? Это должно позволить вам сделать это в строке без создания собственного вектора.

Я не тестировал следующий код, но он должен выглядеть примерно так (если не точно):

typedef stdext::hash_map<int, Foo *> MyMapType; //see comment.
BOOST_FOREACH( MyMapType::value_type& p, myMap )
{
    delete p.second;
}

Ну это больше чем 1 строка, из-за typedef :)

3
ответ дан 6 December 2019 в 11:48
поделиться

Хорошо, я узнал, как сделать это в одну строку ... но я не думаю, что когда-либо смог бы сделать следующее в реальном коде!

std::for_each( mayMap.begin()
             , myMap.end()
             , boost::bind( &boost::checked_delete<Foo>
                          , boost::bind( &stdext::hash_map<int, Foo *>::value_type::second, _1 ) ) );

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

0
ответ дан 6 December 2019 в 11:48
поделиться

Если это возможно, в карте следует использовать умные указатели.

Использование умных указателей здесь устраняет необходимость рефакторинга и отладки удаления членов. В дальнейшем нужно будет беспокоиться о меньшем управлении памятью. Каждый раз, когда я использую new/delete, я очень хорошо думаю о том, нужно ли это. Личный "запах кода" (по Мартину Фаулеру), если хотите.

Конечно, если ваш старый код возвращает карту, то подход for_each, вероятно, будет лучшим вариантом - но если вы приложили руку к созданию карты, я бы рекомендовал использовать умные указатели.

0
ответ дан 6 December 2019 в 11:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: