如何使用for_each删除STL映射中的每个值?

时间:2010-03-17 15:26:19

标签: c++ algorithm boost stl

假设我有一个STL映射,其中值是指针,我想将它们全部删除。我如何表示以下代码,但是使用std :: for_each?我很高兴能使用Boost的解决方案。

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

(我发现了Boost的checked_delete,但我不确定如何将它应用于迭代器所代表的pair<int, Foo *>

(另外,出于这个问题的目的,忽略存储需要在STL容器中删除的原始指针的事实并不是很明智。)

注意:我随后在下面找到并列出了一个单行答案......但是代码非常糟糕,所以我接受了GMan的理智答案。

4 个答案:

答案 0 :(得分:14)

你必须创建一个函数对象:

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

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

如果你正在使用boost,你也可以使用lambda库:

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

但您可以尝试自动执行此操作的pointer containers库。

请注意,您没有使用地图,而是使用hash_map。我建议你切换到更新的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

答案 1 :(得分:3)

您是否尝试过使用BOOST_FOREACH?这应该允许你在一行中完成,而无需创建自己的仿函数。

我没有测试过以下代码,但它应该看起来像这样(如果不完全正确):

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

那是多于1行,因为typedef:)

答案 2 :(得分:0)

如果可能,您应该在地图中使用智能指针。

这里使用智能指针消除了重构和调试成员删除的需要。一个较少的内存管理担心前进。任何时候我使用new / delete我都认为这是否真的很难。个人“代码味道”(按照Martin Fowler的说法),如果你愿意的话。

当然,如果您的旧代码返回地图,那么for_each方法可能是您最好的选择 - 但如果您有一些创建地图的方法,我建议您使用智能指针。

答案 3 :(得分:0)

好的,我发现如何在一行中做到这一点......但我认为我不会真正在实际代码中执行以下操作!

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的回答,因为我喜欢他对包装容器的想法,而我的回答,尽管按要求是一行,但是只是非常讨厌。