巧妙使用RAII中的ScopeExit
什么是RAII
Resource Acquisition Is Initialization,資源獲取即初始化,將資源的生命周期與一個(gè)對(duì)象的生命周期綁定,舉例來說就是,把一些資源封裝在類中,在構(gòu)造函數(shù)請(qǐng)求資源,在析構(gòu)函數(shù)中釋放資源且絕不拋出異常,而一個(gè)對(duì)象在生命周期結(jié)束時(shí)會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù),即資源的生命周期與一個(gè)對(duì)象的生命周期綁定。
RAII的應(yīng)用
見如下代碼:
std::mutex mutex; void func() {} void NoRAII() { mutex.lock(); func(); if (xxx) { mutex.unlock();// 多次需要調(diào)用unlock(),還有可能忘記調(diào)用unlock導(dǎo)致一直持有鎖 return; } ... mutex.unlock(); } void RAII() { // 不需要顯式調(diào)用unlock std::lock_guard<std::mutex> lock(mutex); func(); if (xxx) { return; } ... return; }
RAII的應(yīng)用非常多,C++的STL基本都遵循RAII規(guī)范,典型的如vector, string, lock_guard, unique_lock, shared_ptr, unique_ptr等,這里不會(huì)介紹這些STL的使用,相信大家也都會(huì)使用,如果有相關(guān)需求可以留言。
RAII的巧用
最近研究了boost中的ScopeExit,發(fā)現(xiàn)這是個(gè)很高級(jí)的特性,利用RAII特性,可以在作用域結(jié)束時(shí)自動(dòng)關(guān)閉已經(jīng)打開的資源或做某些清理操作,類似于unique_ptr,但又比unique_ptr方便,不需要自定義delete函數(shù)。
舉例: 如果沒有ScopeExit
void test () { char *test = new char[100]; if (a) { delete[] test; // count 1 return; } xxx; if (b) { delete[] test; // count 2 return; } ... delete[] test; // count 3 }
使用了ScopeExit
void test () { char *test = new char[100]; std::ofstream ofs("test.txt"); ScopeExit { delete[] test; // 在test函數(shù)生命周期結(jié)束后自動(dòng)執(zhí)行delete[]操作 ofs.close(); // 在生命周期結(jié)束后自動(dòng)關(guān)閉文件,這里只是舉個(gè)不恰當(dāng)例子,ofstream自動(dòng)生命周期結(jié)束后就會(huì)關(guān)閉 }; if (a) { return; } xxx; if (b) { return; } ... }
當(dāng)然,正常C++代碼不鼓勵(lì)使用裸指針,可以使用智能指針來申請(qǐng)資源,這里只是舉個(gè)例子,使用ScopeExit也可以用于處理文件資源的關(guān)閉等等。
兩者代碼比較后優(yōu)劣程度顯而易見,不使用ScopeExit需要在return前多次做資源清理操作,而使用了ScopeExit則只需做一次聲明后在作用域結(jié)束后會(huì)自動(dòng)進(jìn)行相關(guān)的資源清理操作,方便而且不易出錯(cuò)。
ScopeExit實(shí)現(xiàn)
這里參考boost使用C++11實(shí)現(xiàn)了一套ScopeExit機(jī)制
class ScopeExit { public: ScopeExit() = default; ScopeExit(const ScopeExit&) = delete; void operator=(const ScopeExit&) = delete; ScopeExit(ScopeExit&&) = default; ScopeExit& operator=(ScopeExit&&) = default; template <typename F, typename... Args> ScopeExit(F&& f, Args&&... args) { func_ = std::bind(std::forward<F>(f), std::forward<Args>(args)...); } ~ScopeExit() { if (func_) { func_(); } }; private: std::function<void()> func_; }; #define _CONCAT(a, b) a##b #define _MAKE_SCOPE_(line) ScopeExit _CONCAT(defer, line) = [&]() #undef SCOPE_GUARD #define SCOPE_GUARD _MAKE_SCOPE_(__LINE__)
使用方式如下:
void test () { char *test = new char[100]; std::ofstream ofs("test.txt"); SCOPE_GUARD{ delete[] test; ofs.close(); }; if (a) { return; } ... if (b) { return; } ... }
RAII還有很多有趣的妙用,后續(xù)還會(huì)介紹,請(qǐng)持續(xù)關(guān)注。
到此這篇關(guān)于巧妙使用RAII中的ScopeExit的文章就介紹到這了,更多相關(guān)RAII妙用ScopeExit內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C/C++使用API實(shí)現(xiàn)數(shù)據(jù)的壓縮與解壓縮
在Windows編程中,經(jīng)常會(huì)遇到需要對(duì)數(shù)據(jù)進(jìn)行壓縮和解壓縮的情況,本文將深入探討使用Windows API進(jìn)行數(shù)據(jù)壓縮與解壓縮的過程,感興趣的小伙伴可以了解下2023-11-11C++實(shí)現(xiàn)日期計(jì)算器詳細(xì)代碼示例
這篇文章主要給大家介紹了關(guān)于C++實(shí)現(xiàn)日期計(jì)算器的相關(guān)資料,基于C++編寫的簡(jiǎn)單的日期計(jì)算器,供大家參考,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-03-03C++多線程編程時(shí)的數(shù)據(jù)保護(hù)
這篇文章主要介紹了C++多線程編程時(shí)的數(shù)據(jù)保護(hù),作者針對(duì)C++11版本中的新特性做出了一些解說,需要的朋友可以參考下2015-07-07簡(jiǎn)要對(duì)比C語言中三個(gè)用于退出進(jìn)程的函數(shù)
這篇文章主要介紹了C語言中三個(gè)用于退出進(jìn)程的函數(shù)的對(duì)比,分別為_exit()函數(shù)和on_exit()函數(shù)以及atexit()函數(shù),需要的朋友可以參考下2015-08-08哈希表實(shí)驗(yàn)C語言版實(shí)現(xiàn)
以下是對(duì)哈希表實(shí)驗(yàn)用C語言實(shí)現(xiàn)的代碼進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以參考下2013-07-07C++實(shí)現(xiàn)LeetCode(188.買賣股票的最佳時(shí)間之四)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(188.買賣股票的最佳時(shí)間之四),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08C語言實(shí)現(xiàn)學(xué)籍管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)學(xué)籍管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03