C++ 的析構與atexit()

    曾經被問到過這樣兩個問題:

1> 在C/C++中,怎樣在程序退出main函數後仍然進行一些操作,比如資源堆棧方面的清理?

2> 在C++程序中,我們要怎樣才能夠得到程序退出main後對象析構所需要的時間?

 

    我們知道,在C++中,全局對象或者main域中對象的析構,是在退出main函數後進行的。所以對於問題1,我們可以在一個全局對象的析構函數中調用相關的函數來實現。但是,C語言不支持對象,所以這種方法對於C程序就無能爲力了。

 

    對於問題2,我們可以通過對象的構造與析構來勉強實現這一功能。我們可以定義兩個類A,B,其中A的析構函數可以打印出當前時間,B的構造函數可以打印出當前時間,此外A,B什麼也不做。如果我們在所有全局對象的實例定義前定義A的一個實例,而在main函數退出 (return 0 )前定義B的一個實例,那麼這兩個時間的差就是我們所要的。

 

    然而上述對問題2的解決是基於程序中沒有調用exit()函數,若否,對象b就不會被創建,我們也就不能得到想要的時間了。

 

    其實C/C++的CRT中有一個回調函數atexit(...),可以用來註冊需要在程序exit的時候需要調用的函數,詳細請參考:

http://www.cprogramming.com/fod/atexit.html 或者C:/Program Files/Microsoft Visual Studio 8/VC/crt/src/atonexit.c:123 上述問題1可以完全通過atexit函數實現,而問題2則可以通過綜合atexit和對象的析構來完成。事實上,大多數winodws上的C++編譯器,就是通過使用atexit函數來完成全局對象的析構的。

 

    以下代碼演示瞭如何atexit()和對象析構的調用次序,權當拋磚引玉。如果讀者對atexit意猶未盡,可以研讀C/C++的CRT源碼,或者參考俞甲子、石凡、潘愛民著的《程序員的自我修養--鏈接、裝載與庫》的13.3.3 "atexit實現"一節。

 

/*
* Demostrate the atexit() and class destructor usage for C++.
*/

#include <cstdio>
#include <cstdlib>
#include <string>
#include <ctime>

 

void fnExit0 (void)
{

    printf("Exit function 0./n");
    printCurrentTime();
}

 

void fnExit1 (void)
{
    printf( "Exit function 1./n" );
}

 

void fnExit2 (void)
{
    printf ( "Exit function 2./n" );
}

 

void printCurrentTime( void )
{
    struct tm tmp;
    time_t s = time(NULL);
    localtime_s(&tmp, &s);
    printf("Current time at %04d:%02d:%02d:%02d:%02d:%02d/n",
           tmp.tm_year+1900, tmp.tm_mon+1, tmp.tm_mday, tmp.tm_hour,tmp.tm_min,tmp.tm_sec);
}

 

 

class A
{
public:
    A( const char * className ) {
         m_className = className;
         printf( "A::A() for %s /n", m_className );
    }
    ~A() {
         printf( "A::~A() for %s /n", m_className );
         double sum = 0;
         const int N = 1 << 28;
         for ( int i = 0; i < N; i++ ) {
             sum += i * i;
         }
    }
    const char *m_className;
};

 

class B
{
public:
    B ( const char *className ) {
         m_className = className;
         atexit( fnExit0 );
         printf( "A::B() for %s /n", m_className );
    }
    ~B ( ) {
         printf( "B::~B() for %s /n", m_className );
    }
    const char *m_className;
};

 

void funcInMain(void)
{
    A aInMain( "aInMain" );
}

 

B global_B( "global_B" );
A global_A( "global_A" );

 

int _tmain(int argc, _TCHAR* argv[])
{
    printf( "Entering main()/n" );
 
    atexit( printCurrentTime );

 

    atexit( fnExit1 );
    A a1("a1");

 

    funcInMain();

 

    atexit( fnExit2 );
    A a2("a2");
 
    printf( "Exiting main()/n" );
    return 0;
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章