網(wǎng)站首頁 編程語言 正文
本文代碼地址:https://github.com/pengguoqing/samples_code
一、前言
?? 在Go 語言里面有一個(gè) defer 聲明, 它的作用是將函數(shù)調(diào)用保存在列表中, 函數(shù)返回時(shí)依次調(diào)用列表中的函數(shù)。
之前實(shí)現(xiàn)簡易版的智能指針文章中指出, 智能指針內(nèi)部就是利用的 RAII特點(diǎn), 將對(duì)象的聲明周期使用棧來管理。 因此可以借鑒 Go語言中的 defer邏輯, 然后結(jié)合RAII的特點(diǎn)來實(shí)現(xiàn)一個(gè) C++ 版本的 defer, 依次來實(shí)現(xiàn)在當(dāng)前作用域內(nèi)必須要調(diào)用的函數(shù)。
??關(guān)于離開作用域時(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)閉文件, 而且代碼看起來也不夠簡潔。熟悉 RAII 技術(shù)后, 常用的方式是實(shí)現(xiàn)一個(gè)相關(guān) scope 類封裝, 在文件開發(fā)成功后將 FILE 句柄傳入構(gòu)造函數(shù),在離開作用域時(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 類型來構(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)然是是用萬能并且經(jīng)典的 “Hello world!” 了, 哈哈哈。測(cè)試其離開作用域時(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;
}
輸出如下:
原文鏈接:https://blog.csdn.net/PX1525813502/article/details/127834364
相關(guān)推薦
- 2022-08-20 C++詳細(xì)講解內(nèi)存管理工具primitives_C 語言
- 2022-09-01 C++?OpenCV實(shí)戰(zhàn)之形狀識(shí)別_C 語言
- 2022-11-15 ASP.NET?MVC遍歷驗(yàn)證ModelState的錯(cuò)誤信息_實(shí)用技巧
- 2022-12-23 Kotlin?try?catch異常處理i詳解_Android
- 2023-02-06 C++11中l(wèi)onglong超長整型和nullptr初始化空指針_C 語言
- 2022-02-13 pip install dlib報(bào)C++11 is required to use dlib
- 2022-12-06 Python基礎(chǔ)之文件操作及光標(biāo)移動(dòng)詳解_python
- 2022-11-01 AndroidView與Compose框架交互實(shí)現(xiàn)介紹_Android
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支