有生就有死,既然有了singleton对象GDALDriverManger,就要在main函数退出之前销毁它。
前文GDAL singleton的经典错误 已经分析了这是DCLP的模式,最后由一个指针poDM指向被创建出来的唯一的对象。因为是new出来的,自然要找到delete的地方。同样在gdaldrivermanager.cpp文件,在最后的位置,提供了函数GDALDestroyDriverManager用来完成最后的清理工作。 注释提醒,不要在其他线程还在使用GDAL内部的对象时调用该函数。我只会在退出前调用。
/** * \brief Destroy the driver manager. * * Incidently unloads all managed drivers. * * NOTE: This function is not thread safe. It should not be called while * other threads are actively using GDAL. */ void CPL_STDCALL GDALDestroyDriverManager( void ) { // THREADSAFETY: We would like to lock the mutex here, but it // needs to be reacquired within the destructor during driver // deregistration. if( poDM != NULL ) delete poDM; }
static volatile GDALDriverManager *poDM = NULL;
/************************************************************************/ /* ~GDALDriverManager() */ /* */ /* Eventually this should also likely clean up all open */ /* datasets. Or perhaps the drivers that own them should do */ /* that in their destructor? */ /************************************************************************/ GDALDriverManager::~GDALDriverManager() { /* -------------------------------------------------------------------- */ /* Destroy the existing drivers. */ /* -------------------------------------------------------------------- */ while( GetDriverCount() > 0 ) { GDALDriver *poDriver = GetDriver(0); DeregisterDriver(poDriver); delete poDriver; } m_NameDriverMap.clear(); /* -------------------------------------------------------------------- */ /* Cleanup local memory. */ /* -------------------------------------------------------------------- */ VSIFree( papoDrivers ); VSIFree( pszHome ); /* -------------------------------------------------------------------- */ /* Cleanup any Proxy related memory. */ /* -------------------------------------------------------------------- */ PamCleanProxyDB(); /* -------------------------------------------------------------------- */ /* Blow away all the finder hints paths. We really shouldn't */ /* be doing all of them, but it is currently hard to keep track */ /* of those that actually belong to us. */ /* -------------------------------------------------------------------- */ CPLFinderClean(); CPLFreeConfig(); /* -------------------------------------------------------------------- */ /* Cleanup any memory allocated by the OGRSpatialReference */ /* related subsystem. */ /* -------------------------------------------------------------------- */ OSRCleanup(); /* -------------------------------------------------------------------- */ /* Cleanup VSIFileManager. */ /* -------------------------------------------------------------------- */ VSICleanupFileManager(); /* -------------------------------------------------------------------- */ /* Cleanup thread local storage ... I hope the program is all */ /* done with GDAL/OGR! */ /* -------------------------------------------------------------------- */ CPLCleanupTLS(); /* -------------------------------------------------------------------- */ /* Ensure the global driver manager pointer is NULLed out. */ /* -------------------------------------------------------------------- */ if( poDM == this ) poDM = NULL; }
这个析构函数的注释很奇怪,居然提问,是不是应该让driver的析构函数负责清理工作。当然应该这样。这也带来个疑问,这些driver的析构函数还是有必要看一下。
如果看官方API Reference文档,只能看到公有成员的描述,所以如果想把握GDAL内部的运行原理,只有看代码是唯一的有效方式。
http://www.gdal.org/classGDALDriverManager.html
delete poDriver会导致GDALDriver析构函数被调用,
GDALDriver::~GDALDriver() { if( pfnUnloadDriver != NULL ) pfnUnloadDriver( this ); }这个GDALDriver没有采用常规的C++多态方式,即不同的driver用不同子类来实现,而是用了函数指针的方式。典型C风格!
如果是GeoTiff驱动时,会调用到geotiff.cpp文件的函数:
/************************************************************************/ /* GDALDeregister_GTiff() */ /************************************************************************/ void GDALDeregister_GTiff( GDALDriver * ) { CPLDebug( "GDAL", "GDALDeregister_GTiff() called." ); CSVDeaccess( NULL ); #if defined(LIBGEOTIFF_VERSION) && LIBGEOTIFF_VERSION > 1150 GTIFDeaccessCSV(); #endif }
void GTIFDeaccessCSV() { CSVDeaccess( NULL ); }
获许因为没什么东西真的不需要清理,或许是bug。暂时还说不准,我只是对这种用C函数指针代替虚函数的设计究竟能带来多少好处,表示怀疑。