網站首頁 編程語言 正文
本文代碼地址:https://github.com/pengguoqing/samples_code
一、前言
?? 在Go 語言里面有一個 defer 聲明, 它的作用是將函數調用保存在列表中, 函數返回時依次調用列表中的函數。
之前實現簡易版的智能指針文章中指出, 智能指針內部就是利用的 RAII特點, 將對象的聲明周期使用棧來管理。 因此可以借鑒 Go語言中的 defer邏輯, 然后結合RAII的特點來實現一個 C++ 版本的 defer, 依次來實現在當前作用域內必須要調用的函數。
??關于離開作用域時某些函數必須調用的一個經典例子就是文件的關閉, 如下:
FILE *file = fopen("readme.ext", "rb");
if (file == NULL)
{
return;
}
if (caseOne)
{
// dosomething
fclose(file); // 必須手動關閉文件
return;
}
//caseTwo
//dosomething
fclose(file); // 必須手動關閉文件
return;
?? 這種情況下需要顯示的在多個 return 的之前調用 fclose(file)關閉文件, 一方面維護的時候可能會忘記關閉文件, 而且代碼看起來也不夠簡潔。熟悉 RAII 技術后, 常用的方式是實現一個相關 scope 類封裝, 在文件開發成功后將 FILE 句柄傳入構造函數,在離開作用域時利用棧資源銷毀調用 scope 類的析構函數 關閉文件。這當前時一種解決方案, 但是每當遇到一個這種場景時就需要手動封裝一個相關的 scope 類。所以需要一個 類似 defer的東西方便使用。
二、實現
2.1 相關技術
①編譯器類型自動推導;
②Lambda表達式(仿函數);
③RAII;
④轉發引用
2.2 實現
??對函數調用只需要一次, 所以需要類似 unique_ptr的方式, 管理仿函數對象的類只能被移動, 不能被拷貝和賦值,聲明如下:
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;
類成員只需要一個仿函數對象和一個是否有效的標志:
private:
?? ?Functor ?m_func;
?? ?bool ? ? m_valid;
2.3 對外接口
??以宏的方式對外提供調用, 利用 Lambda表達式封裝需要調用的函數,畢竟它的內部就是一個實現仿函數的類, 再讓編譯器自動推導 Lambda 類型來構造一個 CXDeferImpl實例, 每次 defer() 聲明都創建一個對象 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;})
三、測試
??當然是是用萬能并且經典的 “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;
}
輸出如下:
原文鏈接:https://blog.csdn.net/PX1525813502/article/details/127834364
相關推薦
- 2022-06-08 換掉你的@RefreshScope吧
- 2023-05-31 Pandas中map(),applymap(),apply()函數的使用方法_python
- 2024-02-26 openJDK awt 字體支持
- 2022-04-03 Pytorch寫數字識別LeNet模型_python
- 2022-06-14 Qt拖放操作和打印操作的實現_C 語言
- 2022-10-21 tomcat8中startup可以啟動tomcat8w無法啟動的問題分析_Tomcat
- 2022-07-03 Golang之空結構體和零長數組的實踐
- 2023-08-01 elementui全局給select option添加title屬性
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支