清理 STL 指针列表/向量

发布于 2024-07-08 13:16:22 字数 185 浏览 4 评论 0原文

您可以使用最短的 C++ 块来安全地清理 std::vectorstd::list 指针? (假设您必须对指针调用删除?)

list<Foo*> foo_list;

我宁愿不使用 Boost 或用智能指针包装我的指针。

What is the shortest chunk of C++ you can come up with to safely clean up a std::vector or std::list of pointers? (assuming you have to call delete on the pointers?)

list<Foo*> foo_list;

I'd rather not use Boost or wrap my pointers with smart pointers.

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

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

发布评论

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

评论(15

情释 2024-07-15 13:16:23

对于 std::list 使用:

while(!foo.empty()) delete foo.front(), foo.pop_front();

对于 std::vector 使用:

while(!bar.empty()) delete bar.back(), bar.pop_back();

不知道为什么我采取 front 而不是上面的 std::listback 。 我想就是感觉速度变快了。 但实际上两者都是恒定时间:)。 不管怎样,将它包装成一个函数并享受乐趣:

template<typename Container>
void delete_them(Container& c) { while(!c.empty()) delete c.back(), c.pop_back(); }

For std::list<T*> use:

while(!foo.empty()) delete foo.front(), foo.pop_front();

For std::vector<T*> use:

while(!bar.empty()) delete bar.back(), bar.pop_back();

Not sure why i took front instead of back for std::list above. I guess it's the feeling that it's faster. But actually both are constant time :). Anyway wrap it into a function and have fun:

template<typename Container>
void delete_them(Container& c) { while(!c.empty()) delete c.back(), c.pop_back(); }
初见你 2024-07-15 13:16:23

既然我们在这里发出挑战...“C++ 的最短部分”,

static bool deleteAll( Foo * theElement ) { delete theElement; return true; }

foo_list . remove_if ( deleteAll );

我认为我们可以相信那些提出 STL 的人拥有高效的算法。 为什么要重新发明轮子?

Since we are throwing down the gauntlet here... "Shortest chunk of C++"

static bool deleteAll( Foo * theElement ) { delete theElement; return true; }

foo_list . remove_if ( deleteAll );

I think we can trust the folks who came up with STL to have efficient algorithms. Why reinvent the wheel?

冬天的雪花 2024-07-15 13:16:23
for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); ++it)
{
    delete *it;
} 
foo_list.clear();
for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); ++it)
{
    delete *it;
} 
foo_list.clear();
天冷不及心凉 2024-07-15 13:16:23

如果你允许 C++11,你可以做 Douglas Leeder 答案的一个非常简短的版本:

for(auto &it:foo_list) delete it; foo_list.clear();

If you allow C++11, you can do a very short version of Douglas Leeder's answer:

for(auto &it:foo_list) delete it; foo_list.clear();
眼前雾蒙蒙 2024-07-15 13:16:23

依赖容器外部的代码来删除指针确实很危险。 例如,当容器由于抛出异常而被销毁时会发生什么?

我知道你说过你不喜欢 boost,但请考虑 增强指针容器

It's really dangerous to rely on code outside of the container to delete your pointers. What happens when the container is destroyed due to a thrown exception, for example?

I know you said you don't like boost, but please consider the boost pointer containers.

欲拥i 2024-07-15 13:16:23
template< typename T >
struct delete_ptr : public std::unary_function<T,bool>
{
   bool operator()(T*pT) const { delete pT; return true; }
};

std::for_each(foo_list.begin(), foo_list.end(), delete_ptr<Foo>());
template< typename T >
struct delete_ptr : public std::unary_function<T,bool>
{
   bool operator()(T*pT) const { delete pT; return true; }
};

std::for_each(foo_list.begin(), foo_list.end(), delete_ptr<Foo>());
戴着白色围巾的女孩 2024-07-15 13:16:23

我不确定函子方法是否会在此处胜出。

for( list<Foo*>::iterator i = foo_list.begin(); i != foo_list.end(); ++i )
    delete *i;

不过,我通常会建议不要这样做。 一般来说,将指针包装在智能指针中或使用专门的指针容器会更加健壮。 有很多方法可以从列表中删除项目(各种类型的eraseclear、销毁列表、通过迭代器分配到列表中等。 )。 你能保证把他们全部抓到吗?

I'm not sure that the functor approach wins for brevity here.

for( list<Foo*>::iterator i = foo_list.begin(); i != foo_list.end(); ++i )
    delete *i;

I'd usually advise against this, though. Wrapping the pointers in smart pointers or using a specialist pointer container is, in general, going to be more robust. There are lots of ways that items can be removed from a list ( various flavours of erase, clear, destruction of the list, assignment via an iterator into the list, etc. ). Can you guarantee to catch them all?

锦上情书 2024-07-15 13:16:23

当您的列表超出使用 RAII 的范围或调用 list::clear() 时,以下 hack 会删除指针。

template <typename T>
class Deleter {
public:
  Deleter(T* pointer) : pointer_(pointer) { }
  Deleter(const Deleter& deleter) {
    Deleter* d = const_cast<Deleter*>(&deleter);
    pointer_ = d->pointer_;
    d->pointer_ = 0;
  }
  ~Deleter() { delete pointer_; }
  T* pointer_;
};

例子:

std::list<Deleter<Foo> > foo_list;
foo_list.push_back(new Foo());
foo_list.clear();

The following hack deletes the pointers when your list goes out of scope using RAII or if you call list::clear().

template <typename T>
class Deleter {
public:
  Deleter(T* pointer) : pointer_(pointer) { }
  Deleter(const Deleter& deleter) {
    Deleter* d = const_cast<Deleter*>(&deleter);
    pointer_ = d->pointer_;
    d->pointer_ = 0;
  }
  ~Deleter() { delete pointer_; }
  T* pointer_;
};

Example:

std::list<Deleter<Foo> > foo_list;
foo_list.push_back(new Foo());
foo_list.clear();
っ左 2024-07-15 13:16:23

至少对于一个列表来说,迭代和删除,然后在最后调用clear有点低效,因为它涉及遍历列表两次,而实际上你只需要执行一次。 这是一个更好的方法:

for (list<Foo*>::iterator i = foo_list.begin(), e = foo_list.end(); i != e; )
{
    list<Foo*>::iterator tmp(i++);
    delete *tmp;
    foo_list.erase(tmp);
}

也就是说,您的编译器可能足够聪明,可以循环组合两者,具体取决于 list::clear 的实现方式。

At least for a list, iterating and deleting, then calling clear at the end is a bit inneficient since it involves traversing the list twice, when you really only have to do it once. Here is a little better way:

for (list<Foo*>::iterator i = foo_list.begin(), e = foo_list.end(); i != e; )
{
    list<Foo*>::iterator tmp(i++);
    delete *tmp;
    foo_list.erase(tmp);
}

That said, your compiler may be smart enough to loop combine the two anyways, depending on how list::clear is implemented.

各自安好 2024-07-15 13:16:23

实际上,我相信 STD 库以 的形式提供了管理内存的直接方法allocator 类

您可以扩展基本分配器的 deallocate() 方法来自动删除任何容器的成员。

我/认为/这就是它的用途。

Actually, I believe the STD library provides a direct method of managing memory in the form of the allocator class

You can extend the basic allocator's deallocate() method to automatically delete the members of any container.

I /think/ this is the type of thing it's intended for.

靑春怀旧 2024-07-15 13:16:23
for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); it++)
{
    delete *it;
} 
foo_list.clear();

您不想这样做有一个小原因 - 您实际上是在列表上迭代两次。

std::list<>::clear 的复杂度是线性的; 它在循环中一次删除并销毁一个元素。

考虑到上述内容,我认为最简单的阅读解决方案是:

while(!foo_list.empty())
{
    delete foo_list.front();
    foo_list.pop_front();
}
for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); it++)
{
    delete *it;
} 
foo_list.clear();

There's a small reason why you would not want to do this - you're effectively iterating over the list twice.

std::list<>::clear is linear in complexity; it removes and destroys one element at a time within a loop.

Taking the above into consideration the simplest to read solution in my opinion is:

while(!foo_list.empty())
{
    delete foo_list.front();
    foo_list.pop_front();
}
清音悠歌 2024-07-15 13:16:23

自 C++11 起:

std::vector<Type*> v;
...
std::for_each(v.begin(), v.end(), std::default_delete<Type>());

或者,如果您正在编写模板化代码并希望避免指定具体类型:

std::for_each(v.begin(), v.end(),
    std::default_delete<std::remove_pointer<decltype(v)::value_type>::type>());

其中(自 C++14 起)可以缩短为:

std::for_each(v.begin(), v.end(),
    std::default_delete<std::remove_pointer_t<decltype(v)::value_type>>());

Since C++11:

std::vector<Type*> v;
...
std::for_each(v.begin(), v.end(), std::default_delete<Type>());

Or, if you are writing templated code and want to avoid specifying a concrete type:

std::for_each(v.begin(), v.end(),
    std::default_delete<std::remove_pointer<decltype(v)::value_type>::type>());

Which (since C++14) can be shortened as:

std::for_each(v.begin(), v.end(),
    std::default_delete<std::remove_pointer_t<decltype(v)::value_type>>());
缘字诀 2024-07-15 13:16:23
void remove(Foo* foo) { delete foo; }
....
for_each( foo_list.begin(), foo_list.end(), remove );
void remove(Foo* foo) { delete foo; }
....
for_each( foo_list.begin(), foo_list.end(), remove );
焚却相思 2024-07-15 13:16:23

在我看来,这似乎是最干净的,但是你的 c++ 版本必须支持这种类型的迭代(我相信任何包含或在 c++0x 之前的内容都可以工作):

for (Object *i : container) delete i;    
container.clear();

This seems cleanest imo, but your c++ version must support this type of iteration (I believe anything including or ahead of c++0x will work):

for (Object *i : container) delete i;    
container.clear();
做个ˇ局外人 2024-07-15 13:16:23
for (list<Foo*>::const_iterator i = foo_list.begin(), e = foo_list.end(); i != e; ++i)
    delete *i;
foo_list.clear();
for (list<Foo*>::const_iterator i = foo_list.begin(), e = foo_list.end(); i != e; ++i)
    delete *i;
foo_list.clear();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文