C++實(shí)現(xiàn)defer聲明方法詳解
本文代碼地址:https://github.com/pengguoqing/samples_code
一、前言
在Go 語(yǔ)言里面有一個(gè) defer 聲明, 它的作用是將函數(shù)調(diào)用保存在列表中, 函數(shù)返回時(shí)依次調(diào)用列表中的函數(shù)。
之前實(shí)現(xiàn)簡(jiǎn)易版的智能指針文章中指出, 智能指針內(nèi)部就是利用的 RAII特點(diǎn), 將對(duì)象的聲明周期使用棧來(lái)管理。 因此可以借鑒 Go語(yǔ)言中的 defer邏輯, 然后結(jié)合RAII的特點(diǎn)來(lái)實(shí)現(xiàn)一個(gè) C++ 版本的 defer, 依次來(lái)實(shí)現(xiàn)在當(dāng)前作用域內(nèi)必須要調(diào)用的函數(shù)。
關(guān)于離開(kāi)作用域時(shí)某些函數(shù)必須調(diào)用的一個(gè)經(jīng)典例子就是文件的關(guān)閉, 如下:
FILE *file = fopen("readme.ext", "rb");
if (file == NULL)
{
return;
}
if (caseOne)
{
// dosomething
fclose(file); // 必須手動(dòng)關(guān)閉文件
return;
}
//caseTwo
//dosomething
fclose(file); // 必須手動(dòng)關(guān)閉文件
return;這種情況下需要顯示的在多個(gè) return 的之前調(diào)用 fclose(file)關(guān)閉文件, 一方面維護(hù)的時(shí)候可能會(huì)忘記關(guān)閉文件, 而且代碼看起來(lái)也不夠簡(jiǎn)潔。熟悉 RAII 技術(shù)后, 常用的方式是實(shí)現(xiàn)一個(gè)相關(guān) scope 類封裝, 在文件開(kāi)發(fā)成功后將 FILE 句柄傳入構(gòu)造函數(shù),在離開(kāi)作用域時(shí)利用棧資源銷毀調(diào)用 scope 類的析構(gòu)函數(shù) 關(guān)閉文件。這當(dāng)前時(shí)一種解決方案, 但是每當(dāng)遇到一個(gè)這種場(chǎng)景時(shí)就需要手動(dòng)封裝一個(gè)相關(guān)的 scope 類。所以需要一個(gè) 類似 defer的東西方便使用。
二、實(shí)現(xiàn)
2.1 相關(guān)技術(shù)
①編譯器類型自動(dòng)推導(dǎo);
②Lambda表達(dá)式(仿函數(shù));
③RAII;
④轉(zhuǎn)發(fā)引用
2.2 實(shí)現(xiàn)
對(duì)函數(shù)調(diào)用只需要一次, 所以需要類似 unique_ptr的方式, 管理仿函數(shù)對(duì)象的類只能被移動(dòng), 不能被拷貝和賦值,聲明如下:
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;
類成員只需要一個(gè)仿函數(shù)對(duì)象和一個(gè)是否有效的標(biāo)志:
private:
Functor m_func;
bool m_valid;
2.3 對(duì)外接口
以宏的方式對(duì)外提供調(diào)用, 利用 Lambda表達(dá)式封裝需要調(diào)用的函數(shù),畢竟它的內(nèi)部就是一個(gè)實(shí)現(xiàn)仿函數(shù)的類, 再讓編譯器自動(dòng)推導(dǎo) Lambda 類型來(lái)構(gòu)造一個(gè) CXDeferImpl實(shí)例, 每次 defer() 聲明都創(chuàng)建一個(gè)對(duì)象 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;})三、測(cè)試
當(dāng)然是是用萬(wàn)能并且經(jīng)典的 “Hello world!” 了, 哈哈哈。測(cè)試其離開(kāi)作用域時(shí)能不能完整的輸出的 “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++實(shí)現(xiàn)defer聲明方法詳解的文章就介紹到這了,更多相關(guān)C++ defer內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++結(jié)構(gòu)體中變長(zhǎng)數(shù)組的使用問(wèn)題分解刨析
變長(zhǎng)數(shù)組在C++中指的是集合(也叫容器)如vector就是C語(yǔ)言中,所有的數(shù)組都不定長(zhǎng),沒(méi)有下標(biāo)越界的概念,數(shù)組實(shí)質(zhì)就是一個(gè)指針(由數(shù)組名充當(dāng))因此C語(yǔ)言中數(shù)組的長(zhǎng)度沒(méi)有任何意義平常在C語(yǔ)言中講的不定長(zhǎng)數(shù)組,其實(shí)就是指針2022-08-08
C語(yǔ)言實(shí)現(xiàn)模擬USB對(duì)8bit數(shù)據(jù)的NRZI編碼輸出
今天小編就為大家分享一篇關(guān)于C語(yǔ)言實(shí)現(xiàn)模擬USB對(duì)8bit數(shù)據(jù)的NRZI編碼輸出,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12
C語(yǔ)言聯(lián)合體Union特點(diǎn)及運(yùn)用全面講解教程
這篇文章主要為大家介紹了C語(yǔ)言聯(lián)合體Union特點(diǎn)及運(yùn)用的全面講解教程有需要深度朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2021-10-10
C語(yǔ)言使用openSSL庫(kù)AES模塊實(shí)現(xiàn)加密功能詳解
這篇文章主要介紹了C語(yǔ)言使用openSSL庫(kù)AES模塊實(shí)現(xiàn)加密功能,詳細(xì)分析了C語(yǔ)言加密的相關(guān)概念、原理及AES模塊加密具體實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-05-05
C語(yǔ)言實(shí)現(xiàn)掃雷游戲(可展開(kāi))
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)掃雷游戲,實(shí)現(xiàn)掃雷展開(kāi)和提醒,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-03-03
探討:C++實(shí)現(xiàn)鏈?zhǔn)蕉鏄?shù)(用非遞歸方式先序,中序,后序遍歷二叉樹(shù))
本篇文章是對(duì)用C++實(shí)現(xiàn)鏈?zhǔn)蕉鏄?shù)(用非遞歸方式先序,中序,后序遍歷二叉樹(shù))的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
c++入門必學(xué)庫(kù)函數(shù)sort的基本用法
Sort函數(shù)包含在頭文件為#include<algorithm>的c++標(biāo)準(zhǔn)庫(kù)中,調(diào)用標(biāo)準(zhǔn)庫(kù)里的排序方法可以不必知道其內(nèi)部是如何實(shí)現(xiàn)的,只要出現(xiàn)我們想要的結(jié)果即可,下面這篇文章主要給大家介紹了關(guān)于c++入門必學(xué)庫(kù)函數(shù)sort的基本用法,需要的朋友可以參考下2022-11-11
使用C++中的ADO對(duì)SQLite進(jìn)行增刪改查
本文將介紹如何使用C++的ADO (ActiveX Data Objects)對(duì)SQLite數(shù)據(jù)庫(kù)進(jìn)行增刪改查操作,文中有詳細(xì)的代碼示例,需要的朋友可以參考下2023-06-06

