50

你能想出的最短的 C++ 块是什么来安全地清理 a std::vectoror std::listof 指针?(假设您必须在指针上调用 delete ?)

list<Foo*> foo_list;

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

4

15 回答 15

57

使用std::list<T*>

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

使用std::vector<T*>

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

不知道为什么我拿了上面的而front不是上面的。我想这是感觉它更快。但实际上两者都是恒定的时间:)。无论如何将其包装成一个函数并玩得开心:backstd::list

template<typename Container>
void delete_them(Container& c) { while(!c.empty()) delete c.back(), c.pop_back(); }
于 2008-11-20T22:50:23.237 回答
52

既然我们在这里放弃了挑战……“最短的 C++ 块”

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

foo_list . remove_if ( deleteAll );

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

于 2008-11-21T00:06:05.457 回答
31
for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); ++it)
{
    delete *it;
} 
foo_list.clear();
于 2008-11-20T22:29:59.673 回答
16

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

for(auto &it:foo_list) delete it; foo_list.clear();
于 2014-02-12T22:04:31.250 回答
13

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

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

于 2008-11-20T23:14:26.247 回答
10
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>());
于 2008-11-20T22:23:46.567 回答
5

为了简洁起见,我不确定仿函数方法是否会获胜。

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

不过,我通常会建议不要这样做。通常,将指针包装在智能指针中或使用专门的指针容器会更加健壮。有很多方法可以从列表中删除项目(各种风格的erase, clear,列表的破坏,通过迭代器分配到列表中,等等)。你能保证全部抓到吗?

于 2008-11-20T22:30:26.677 回答
5

当您的列表使用 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();
于 2012-04-30T11:33:49.770 回答
4

至少对于一个列表,迭代和删除,然后在最后调用 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 的实现方式。

于 2008-11-20T23:19:01.323 回答
4

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

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

我/认为/这是它的用途类型。

于 2010-04-19T20:34:30.303 回答
4
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();
}
于 2014-04-10T06:32:46.813 回答
3

从 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>>());
于 2014-09-16T11:30:16.510 回答
1
void remove(Foo* foo) { delete foo; }
....
for_each( foo_list.begin(), foo_list.end(), remove );
于 2013-12-05T16:01:55.640 回答
0
for (list<Foo*>::const_iterator i = foo_list.begin(), e = foo_list.end(); i != e; ++i)
    delete *i;
foo_list.clear();
于 2008-11-20T22:30:30.670 回答
0

这似乎是最干净的 imo,但是您的 c++ 版本必须支持这种类型的迭代(我相信包括或在 c++0x 之前的任何东西都可以使用):

for (Object *i : container) delete i;    
container.clear();
于 2018-07-02T18:53:04.227 回答