私が自分のプロジェクトに取り組んでいたときに、これを偶然に発見しました。基本的に、私のプロジェクトでは、リソース処理のために以下のようなものがあります。
class Resource {
public:
static Resource instance_;
~Resource () {
std::for_each(res_.begin(), res_.end(), [&] (Stuff *stuff) {
delete stuff;
});
}
private:
std::set<Stuff*> res_;
};
これをもう一度valgrindで実行すると、プログラムの終了時に、いくつかの本当に不可解なエラーが表示されます。このようなもの:
by 0x40DD42: std::_Rb_tree<unsigned int, std::pair<unsigned int const, std::pair<Vertex*, unsigned int> >,
std::_Select1st<std::pair<unsigned int const, std::pair<Vertex*, unsigned int> > >, std::less<unsigned int>,
std::allocator<std::pair<unsigned int const, std::pair<Vertex*, unsigned int> > > >::equal_range(unsigned int const&)
\\ a lot, lot more to come...
Resource
これらすべてを読むと、のデストラクタがすでに解放されているメモリ領域を解放していることを示しているようです。
しかし、私のデストラクタは間違いなく物事を正しく処理しています。これを証明するために、削除コードをデストラクタから別のメンバー関数に移動しました。だから、このようなもの:
class Resource {
public:
static Resource instance_;
~Resource () { /* does nothing */ }
void clear () {
std::for_each(res_.begin(), res_.end(), [&] (Stuff *stuff) {
delete stuff;
});
}
// ... more
};
次に、プログラムが終了する前に、静的インスタンスでclear()を呼び出すだけです。これで、valgrindにエラーが表示されなくなりました。
これが、プログラムが停止したときに静的インスタンスが停止した場合にのみ関係することをさらに証明するために、静的インスタンスを削除しました。静的なinstance_を使用する代わりに、プログラムの起動時Resource
にスタック上のインスタンスを割り当てました。main()
この変更後、問題もなくなります。
さて、なぜこれが起こっているのだろうか?これはオペレーティングシステムと関係がありますか?
私の推測では、OSはおそらくプログラムが終了するときにすべてを解放しようとし、私のデストラクタはクリーンアップの前ではなく、クリーンアップ中にたまたま起動します。
ここで問題となっているOSはLinux(Ubuntu 12.10)です。コンパイラはgcc4.7.2です。
ありがとう