前往
大廳
主題

C語言變數生命週期觀察與Lambda運算式入門

Yang | 2024-01-28 10:59:21 | 巴幣 0 | 人氣 101

接續以前寫的:
C取時間和指標使用上的一些眉角
C在編譯時帶入的變數

一般變數不太容易觀察生命週期,還好class在建立(new)和消滅(delete)時,會呼叫建構子(Constructor)和解構子(Destructor),在裡面加入log觀察,幫助理解加深記憶

Lambda運算式在C#很常見,但是C的Lambda功能更多也更複雜,

這裡先用來觀察建構子和解構子,更多的應用範例待以後的文章補充

#define STR(N) #N
#define XSTR(N) STR(N)

//__LINE__型態是%d,利用XSTR轉換成%s
#define _LINE_STR_ XSTR(__LINE__)

class MyClass
{
    public:
    MyClass()
    {
        printf("Constructor|%s|%s", _LINE_STR_, __FUNCTION__); //__FUNCTION__=="MyClass"
    }

    public:
    ~MyClass()
    {
        printf("Destructor|%s|%s", _LINE_STR_, __FUNCTION__); //__FUNCTION__=="~MyClass"
    }

    public:
    static MyClass *Factory()
    {
        return new MyClass();
    }
};

int main(const int argc, const char *argv[])
{
    { //_mf0只會活在大括弧內,離開大括弧時,會觸發解構子
        const MyClass _mf0();
    }

    { //Lambda練習1
        auto lambda = [](void) { return new MyClass(); }; //離開大括弧時,不會觸發解構子

        const MyClass *_mf1 = lambda();

        delete _mf1; //觸發解構子
    }

    { //Lambda練習2
        std::function<MyClass *()> func = MyClass::Factory; //離開大括弧時,不會觸發解構子

        const MyClass *_mf2 = func();

        delete _mf2; //觸發解構子
        delete _mf2; //程式當掉
    }

    return EXIT_SUCCESS;
}

Lambda練習1和練習2推測是等價的語法,觀察執行時間都小於1 usec,看不出效能差異

Lambda練習2的彈性更廣,能當作變數傳遞給別的函式使用

多delete一次就會使程式當掉,會有類似以下的錯誤訊息,不同平台訊息可能不一樣,但程式都會當掉:
Exception has occurred.
Aborted

double free or corruption (fasttop): 0x0000000000646030 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x81299)[0x7ffff7052299]

當掉這點看來是沒救了,沒找到方法是能讓程式繼續往下執行的

結論C語言是有借有還的語言,借多少就要還多少,
還少一點(Memory Leak),程式可能可以跑久一點,直到吃光機器的記憶體形成大災難,
還多一點,立刻當掉沒得救

20240129補充Lambda練習3,紀錄
1.重複使用指標,忘記釋放記憶體的情況
2.多一層NULL判斷,避免重複delete,但是程式碼會很醜

MyClass *_mcPtr = NULL;

{ //區塊1
    auto lambda = [](void) { return new MyClass(); };

    _mcPtr = lambda();
}

{ //區塊2
    std::function<MyClass *()> func = MyClass::Factory;

    _mcPtr = func(); //重複使用指標,忘記釋放區塊1(Memory Leak)

    //後來發現以下程式碼是不好的寫法,之後再補充修正
    if (_mcPtr != NULL)
    {
        delete _mcPtr; //觸發區塊2解構子
    }
    _mcPtr = NULL;
}

if (_mcPtr != NULL) //多一層NULL判斷,避免重複delete
{
    delete _mcPtr; //程式不會當掉,但是區塊1變成沒用的孤兒記憶體,直到程式結束
}
_mcPtr = NULL;
送禮物贊助創作者 !
0
留言

創作回應

更多創作