我今天在做我的项目时偶然发现了这一点。基本上,在我的项目中,我有类似于下面的资源处理。
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 中!
为了进一步证明这仅与程序死亡时静态实例死亡有关,我删除了静态实例。在我的程序启动时,我只是Resource
在堆栈上分配了一个实例,而不是静态实例。main()
在此更改之后,问题也消失了。
现在,我想知道为什么会这样?这和操作系统有关系吗?
我的猜测是,操作系统可能会在程序终止时尝试释放所有内容,而我的析构函数恰好在清理过程中启动,而不是之前。
这里有问题的操作系统是 Linux (Ubuntu 12.10)。编译器是 gcc 4.7.2。
谢谢