GDALDestroyDriverManager 分析

有生就有死,既然有了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;
}

poDM也定义在这个文件开头,是一个静态指针。

static volatile GDALDriverManager        *poDM = NULL;


delete poDM会引发GDALDriverManager的析构函数被执行,看一下析构函数代码,的确做了不少工作。所以那种GDALDestroyDriverManager函数不需要调用的观点是错误的。

/************************************************************************/
/*                         ~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 );
}

结果追踪下来,driver没有什么有效代码做清理。除了GDALDriver的析构函数做了默认的清理以外。

获许因为没什么东西真的不需要清理,或许是bug。暂时还说不准,我只是对这种用C函数指针代替虚函数的设计究竟能带来多少好处,表示怀疑。


你可能感兴趣的:(GDALDestroyDriverManager 分析)