起因
一个基础库中对资源回收的行为出现异常,经过排查,发现是基础库实现时对虚函数的调用出现问题造成的,记录下来吧。
纯虚函数的版本
#include <iostream>
using namespace std;
class B
{
public:
~B()
{
close();
}
void close()
{
doClose();
}
virtual void doClose() = 0;
};
class D : public B
{
virtual void doClose()
{
cout <<"D::doClose()" <<endl;
}
};
int main(int argc, char *argv[])
{
B * p = new D();
p->close();
delete p;
return 0;
}
# g++ main.cpp && ./a.out
D::doClose()
pure virtual method called
terminate called without an active exception
Aborted
这里很好理解,D先于B析构,之后的doClose就没有对应的函数可用。
普通虚函数版本
#include <iostream>
using namespace std;
class B
{
public:
~B()
{
close();
}
void close()
{
doClose();
}
virtual void doClose()
{
cout <<"B::doClose()" <<endl;
}
};
class D : public B
{
virtual void doClose()
{
cout <<"D::doClose()" <<endl;
}
};
int main(int argc, char *argv[])
{
B * p = new D();
p->close();
delete p;
return 0;
}
# g++ main.cpp && ./a.out
D::doClose()
B::doClose()
道理也很好理解,D析构后,B析构时调用的doClose指向B::doClose的实现,出现问题的代码逻辑就是这种实现。
总结
库中这块代码逻辑的原意是希望在对象析构时释放占用的资源,当释放资源的操作是纯虚函数时,程序异常退出,问题提前出现。而当释放资源的操作是普通虚函数时,问题就被隐藏掉了,如果管理的资源不是非常敏感的资源,问题可能就会被带到上线后再出现,而且排错非常麻烦。
一切的一切还是要看基本功啊