C++實現(xiàn)defer聲明方法詳解
本文代碼地址:https://github.com/pengguoqing/samples_code
一、前言
在Go 語言里面有一個 defer 聲明, 它的作用是將函數(shù)調(diào)用保存在列表中, 函數(shù)返回時依次調(diào)用列表中的函數(shù)。
之前實現(xiàn)簡易版的智能指針文章中指出, 智能指針內(nèi)部就是利用的 RAII特點, 將對象的聲明周期使用棧來管理。 因此可以借鑒 Go語言中的 defer邏輯, 然后結(jié)合RAII的特點來實現(xiàn)一個 C++ 版本的 defer, 依次來實現(xiàn)在當(dāng)前作用域內(nèi)必須要調(diào)用的函數(shù)。
關(guān)于離開作用域時某些函數(shù)必須調(diào)用的一個經(jīng)典例子就是文件的關(guān)閉, 如下:
FILE *file = fopen("readme.ext", "rb"); if (file == NULL) { return; } if (caseOne) { // dosomething fclose(file); // 必須手動關(guān)閉文件 return; } //caseTwo //dosomething fclose(file); // 必須手動關(guān)閉文件 return;
這種情況下需要顯示的在多個 return 的之前調(diào)用 fclose(file)關(guān)閉文件, 一方面維護的時候可能會忘記關(guān)閉文件, 而且代碼看起來也不夠簡潔。熟悉 RAII 技術(shù)后, 常用的方式是實現(xiàn)一個相關(guān) scope 類封裝, 在文件開發(fā)成功后將 FILE 句柄傳入構(gòu)造函數(shù),在離開作用域時利用棧資源銷毀調(diào)用 scope 類的析構(gòu)函數(shù) 關(guān)閉文件。這當(dāng)前時一種解決方案, 但是每當(dāng)遇到一個這種場景時就需要手動封裝一個相關(guān)的 scope 類。所以需要一個 類似 defer的東西方便使用。
二、實現(xiàn)
2.1 相關(guān)技術(shù)
①編譯器類型自動推導(dǎo);
②Lambda表達式(仿函數(shù));
③RAII;
④轉(zhuǎn)發(fā)引用
2.2 實現(xiàn)
對函數(shù)調(diào)用只需要一次, 所以需要類似 unique_ptr的方式, 管理仿函數(shù)對象的類只能被移動, 不能被拷貝和賦值,聲明如下:
public: inline CXDeferImpl(const Functor& functor); inline CXDeferImpl(Functor&& functor); inline CXDeferImpl(CXDeferImpl&& another); inline ~CXDeferImpl(); private: //不允許拷貝, 賦值 CXDeferImpl(const CXDeferImpl& another) = delete; CXDeferImpl operator=(const CXDeferImpl& another) = delete; CXDeferImpl operator=(CXDeferImpl&& another) = delete;
類成員只需要一個仿函數(shù)對象和一個是否有效的標(biāo)志:
private:
Functor m_func;
bool m_valid;
2.3 對外接口
以宏的方式對外提供調(diào)用, 利用 Lambda表達式封裝需要調(diào)用的函數(shù),畢竟它的內(nèi)部就是一個實現(xiàn)仿函數(shù)的類, 再讓編譯器自動推導(dǎo) Lambda 類型來構(gòu)造一個 CXDeferImpl實例, 每次 defer() 聲明都創(chuàng)建一個對象 CXDeferImpl。
#define CONCAT_(a, b, c) a##b##c #define CONCAT(a, b, c) CONCAT_(a, b, c) #define defer(x) \ auto CONCAT(defer_, __LINE__, __COUNTER__) = MakeDeferIns([&]{x;})
三、測試
當(dāng)然是是用萬能并且經(jīng)典的 “Hello world!” 了, 哈哈哈。測試其離開作用域時能不能完整的輸出的 “Hello world!”, 代碼如下:
void TestDefer() { defer(cout<<"world!"<<endl); cout<<"Hello "; } void TestDefer2() { { defer(TestDefer()); cout<<"Test defer in scope"<<endl; } cout << "Test defer are ok?" << endl; defer(cout<<"TestDefer2"<<endl); } void TestDefer3(int a) { { defer(cout << "test param func " << a << endl); } defer(cout << "TestDefer3" << endl); } int main() { TestDefer2(); TestDefer3(100); return 0; }
輸出如下:
到此這篇關(guān)于C++實現(xiàn)defer聲明方法詳解的文章就介紹到這了,更多相關(guān)C++ defer內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言數(shù)據(jù)結(jié)構(gòu)與算法之時間空間復(fù)雜度入門
這篇文章主要為大家介紹了C語言數(shù)據(jù)結(jié)構(gòu)與算法之時間空間復(fù)雜度的入門教程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步2022-02-02C++判斷主機是否處于聯(lián)網(wǎng)狀態(tài)
這篇文章主要為大家詳細介紹了C++判斷主機是否處于聯(lián)網(wǎng)狀態(tài),具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-06-06解讀堆排序算法及用C++實現(xiàn)基于最大堆的堆排序示例
把待排序的數(shù)組構(gòu)造出最大堆是進行堆排序操作的基本方法,這里將帶大家來解讀堆排序算法及用C++實現(xiàn)基于最大堆的堆排序示例,首先從堆排序的概念開始:2016-06-06