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

发布于 2024-08-25 16:17:40 字数 538 浏览 2 评论 0原文

假设我有一个 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)。

(另外,为了解决这个问题,请忽略这样一个事实:在 STL 容器中存储需要删除的原始指针并不是很明智)。

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

Suppose I have a STL map where the values are pointers, and I want to delete them all. How would I represent the following code, but making use of std::for_each? I'm happy for solutions to use Boost.

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

(I've found Boost's checked_delete, but I'm not sure how to apply that to the pair<int, Foo *> that the iterator represents).

(Also, for the purposes of this question, ignore the fact that storing raw pointers that need deleting in an STL container isn't very sensible).

Note: I have subsequently found and listed a one-line answer below... but the code is pretty awful so I've accepted GMan's saner answer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

最美的太阳 2024-09-01 16:17:40

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

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

但是你可以尝试 指针容器 库自动执行此操作。

请注意,您使用的不是映射,而是 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

You have to make a function object:

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

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

If you're using boost, you could also use the lambda library:

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

But you might try the pointer containers library which does this automatically.

Note you are not using a map, but a hash_map. I recommend you switch to boost's unordered_map, which is more current. However, there doesn't seem to be a ptr_unordered_map.

For safety, you should wrap this thing up. For example:

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

And use it like:

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

my_container.container./* ... */

This ensures no matter what, your container will be iterated through with a deleter. (For exceptions, for example.)

Compare:

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
鹊巢 2024-09-01 16:17:40

您是否尝试过使用 BOOST_FOREACH ?这应该允许您在一行中执行此操作,而无需创建自己的函子。

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

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

嗯,由于 typedef 的原因,这超过 1 行:)

Have you tried using BOOST_FOREACH ? That should allow you to do that in a line without creating your own functor.

I have not tested the following code but it should look something like this(if not exactly):

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

Well thats more than 1 line, due to the typedef :)

稀香 2024-09-01 16:17:40

好吧,我发现了如何在一行中完成它......但我不认为我会在真正的代码中实际执行以下操作!

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 的答案,因为我喜欢他关于包装容器的想法,而我的答案尽管按照要求只有一行,但实在是令人讨厌。

OK, I found out how to do it in one line... but I don't think I would ever actually do the following in real code!

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

However I'm going to accept GMan's answer because I like his idea of a wrapped container, and my answer, despite being one line as requested, is just plain nasty.

逐鹿 2024-09-01 16:17:40

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

这里使用智能指针消除了重构和调试成员删除的需要。少了一个需要担心的内存管理问题。每当我使用 new/delete 时,我都会认真思考是否需要这样做。如果你愿意的话,一种个人的“代码气味”(马丁·福勒)。

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

If at all possible, you should use smart pointers in your map.

The use of smart pointers here removes the need to refactor and debug member deletion. One less memory management to worry about going forward. Any time I use new/delete I think really hard about whether that's needed. A personal "code smell" (per Martin Fowler), if you like.

Of course, if your old code returns a map, then the for_each approach is probably your best bet - but if you had some hand in creating the map, I'd recommend using smart pointers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文