清理STL列表/指针向量

时间:2008-11-20 22:21:51

标签: c++ stl

为了安全地清理向量或指针列表,您可以提出最短的C ++块? (假设您必须在指针上调用delete?)

list<Foo*> foo_list;

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

15 个答案:

答案 0 :(得分:53)

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上面的back取了std::list而不是template<typename Container> void delete_them(Container& c) { while(!c.empty()) delete c.back(), c.pop_back(); } 。我想这是感觉它更快。但实际上两者都是恒定时间:)。无论如何将它包装成一个函数并享受乐趣:

{{1}}

答案 1 :(得分:52)

因为我们在这里抛弃了挑战......“最短的C ++”

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

foo_list . remove_if ( deleteAll );

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

答案 2 :(得分:29)

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

答案 3 :(得分:16)

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

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

答案 4 :(得分:13)

依靠容器外部的代码删除指针真的很危险。当容器因抛出异常而被销毁时会发生什么,例如?

我知道你说你不喜欢提升,但请考虑boost pointer containers

答案 5 :(得分:9)

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

答案 6 :(得分:6)

我不确定这里的functor方法是否简洁。

for( list<Foo*>::iterator i = foo_list.begin(); i != foo_list.end(); ++i )
    delete *i;
但是,我通常会建议不要这样做。通常,将指针包装在智能指针中或使用专业指针容器会变得更加健壮。有很多方法可以从列表中删除项目(eraseclear的各种风格,列表的破坏,通过迭代器分配到列表中等等)。你能保证把它们全部抓住吗?

答案 7 :(得分: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();

答案 8 :(得分: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的实现方式。

答案 9 :(得分:4)

实际上,我相信STD库提供了一种以allocator class

形式管理内存的直接方法

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

我想/这是它的目的。

答案 10 :(得分:4)

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

为什么你不想这样做有一个小原因 - 你有效地在列表上迭代两次。

std :: list&lt;&gt; :: clear的复杂程度是线性的;它会在循环中一次删除和销毁一个元素。

考虑到上述因素,我认为最简单的解决方案是:

while(!foo_list.empty())
{
    delete foo_list.front();
    foo_list.pop_front();
}

答案 11 :(得分: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>>());

答案 12 :(得分:1)

void remove(Foo* foo) { delete foo; }
....
for_each( foo_list.begin(), foo_list.end(), remove );

答案 13 :(得分:0)

for (list<Foo*>::const_iterator i = foo_list.begin(), e = foo_list.end(); i != e; ++i)
    delete *i;
foo_list.clear();

答案 14 :(得分:0)

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

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