什麼是C++的最小塊,您可以想出安全清理向量或指針列表的方法? (假設你必須調用指針刪除?)清理指針的STL列表/向量
list<Foo*> foo_list;
我寧可不使用Boost或用智能指針包裝我的指針。
什麼是C++的最小塊,您可以想出安全清理向量或指針列表的方法? (假設你必須調用指針刪除?)清理指針的STL列表/向量
list<Foo*> foo_list;
我寧可不使用Boost或用智能指針包裝我的指針。
因爲我們在這裏拋下戰書......「最短的C++大塊」
static bool deleteAll(Foo * theElement) { delete theElement; return true; }
foo_list . remove_if (deleteAll);
,我認爲我們可以信任誰想出了STL有高效算法的鄉親。爲什麼重新發明輪子?
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>());
for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); ++it)
{
delete *it;
}
foo_list.clear();
我不知道該函子的做法贏得了簡短這裏。
for(list<Foo*>::iterator i = foo_list.begin(); i != foo_list.end(); ++i)
delete *i;
雖然我通常會建議這個。包裝智能指針中的指針或使用專業指針容器通常會更加健壯。有很多方法可以從列表中刪除項目(各種風格的erase
,clear
,銷燬列表,通過迭代器分配到列表中等等)。你能保證把他們都抓住嗎?
爲了簡潔起見,仿函數法可能不會取勝,但這不是什麼大獎。通過使用仿函數,您不必編寫自己的循環,這是軟件中許多缺陷的來源。 – 2008-11-21 15:26:26
具體詢問「最短」的問題。我不知道手動循環是缺陷的主要來源,你能提供一個參考嗎?如果我的團隊成員在爲循環寫一個bug時遇到了問題,我寧願不讓他放鬆一個函子解決方案。 – 2008-11-23 11:55:02
for (list<Foo*>::const_iterator i = foo_list.begin(), e = foo_list.end(); i != e; ++i)
delete *i;
foo_list.clear();
對於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(); }
依靠容器外的代碼來刪除指針是非常危險的。例如,當容器由於拋出的異常而被銷燬時會發生什麼?
我知道你說你不喜歡助推,但請考慮boost pointer containers。
至少對於一個列表來說,迭代和刪除,然後在最後調用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);
}
這就是說,你的編譯器可能是足夠聰明循環二者結合起來反正,這取決於如何目錄::明確的實現。
當您的列表使用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();
void remove(Foo* foo) { delete foo; }
....
for_each(foo_list.begin(), foo_list.end(), remove);
如果讓C++ 11,你可以做道格拉斯Leeder先生的回答很短的版本:
for(auto &it:foo_list) delete it; foo_list.clear();
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();
}
由於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>>());
智能指針(包括Boost :: shared_ptr)會在您很難看到手動完成的情況下刪除您的對象。 – 2010-04-19 20:45:16
依賴容器外的代碼刪除指針是非常危險的。例如,當容器由於拋出的異常而被銷燬時會發生什麼?我知道你說過你不喜歡boost,但請考慮[boost指針容器](http://www.boost.org/doc/libs/1_37_0/libs/ptr_container/doc/ptr_container.html)。 – 2008-11-20 23:14:26
我在第二你的意見 – 2010-03-22 03:52:40