std::vector
またはstd::list
ポインターを安全にクリーンアップするために思いつくことができる C++ の最短のチャンクは何ですか? (ポインタで削除を呼び出す必要があると仮定しますか?)
list<Foo*> foo_list;
Boost を使用したり、ポインターをスマート ポインターでラップしたりしたくありません。
用途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(); }
ここでガントレットを投げているので... 「C++の最短チャンク」
static bool deleteAll( Foo * theElement ) { delete theElement; return true; }
foo_list . remove_if ( deleteAll );
STL を思いついた人々が効率的なアルゴリズムを持っていると信頼できると思います。なぜ車輪を再発明するのですか?
for(list<Foo*>::const_iterator it = foo_list.begin(); it != foo_list.end(); ++it)
{
delete *it;
}
foo_list.clear();
コンテナーの外部のコードに依存してポインターを削除するのは非常に危険です。たとえば、例外がスローされたためにコンテナーが破棄された場合はどうなりますか?
ブーストが嫌いだとおっしゃっていたのは承知していますが、ブースト ポインター コンテナーを検討してください。
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*>::iterator i = foo_list.begin(); i != foo_list.end(); ++i )
delete *i;
ただし、通常はこれに反対することをお勧めします。一般に、ポインタをスマート ポインタにラップするか、専用のポインタ コンテナを使用すると、より堅牢になります。リストからアイテムを削除する方法はたくさんあります (さまざまな種類のerase
、clear
、リストの破棄、イテレータによるリストへの代入など)。それらをすべて捕まえることを保証できますか?
次のハックは、RAII を使用してリストが範囲外になったとき、または 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_;
};
例:
std::list<Deleter<Foo> > foo_list;
foo_list.push_back(new Foo());
foo_list.clear();
実際、STDライブラリは、アロケータクラスの形式でメモリを管理する直接的な方法を提供すると思います。
基本的なアロケータのdeallocate()メソッドを拡張して、任意のコンテナのメンバーを自動的に削除できます。
私は/考える/これはそれが意図されているタイプのものです。
少なくともリストの場合、繰り返して削除し、最後に clear を呼び出すことは、リストを 2 回トラバースする必要があるため、少し非効率的です。もう少し良い方法は次のとおりです。
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 の実装方法によっては、コンパイラが 2 つをループ結合するほどスマートな場合があります。
for (list<Foo*>::const_iterator i = foo_list.begin(), e = foo_list.end(); i != e; ++i)
delete *i;
foo_list.clear();