為什麼這篇idiom例子鄉民發文收入到精華區:因為在idiom例子這個討論話題中,有許多相關的文章在討論,這篇最有參考價值!作者gocpp (cpp)看板C_and_CPP標題[心得] The RAII Idiom時間Sun...
idiom例子 在 LeedsMayi Instagram 的最佳解答
2021-08-18 21:05:56
Don’t talk to him now. He’s a bundle of nerves today. 不要跟他講話。他今天很焦躁。 someone who is extremely nervous and worried 你不覺得這個片語很好笑嗎?一看就覺得很緊張 😝 「一束神經」綁...
RAII 是什麼,或許 C++ 用了很久的人也沒聽過。不過即使沒聽過,
在程式中也應該早已大量應用 RAII 的手法了。
常有人問 C++ 與 C 有何不同,這個問題。簡單地說,C 語言支援的
是單純的程序導向(procedural based) 編程,而 C++ 除此之外還
支援
1.object-based
2.object-oriented
3.generic
這三種編程的觀念。學習 C++ 的時候,不要只侷限在這個 keyword 是
什麼意思,那個標準容器怎麼用(當然,這些還是要懂的),種種微末
細節。更重要的是,必須了解 C++ 所支援與 C 不同的設計概念,在接
觸一個新的語言機制或用法時,最好先了解它之所以「存在的目的」,
為什麼要用到這些手法,和舊的方法相比,「有什麼好處」,又「有什
麼限制」…等等,才是提高整體編程水平的捷徑。
本篇的主題 RAII,其實就是 C++ 所支援,而是 C 所缺乏的第一個主要
的概念: object-based(以物件為基礎的)編程。當然,object based
的範疇遠比 RAII 大的多,RAII 只是其中一部份,但卻是非常重要的一
部份。
RAII 指的是「Resource Acquisition Is Initialisation」,直接的意
思是:「資源獲得即初始化」。意即:一旦在程式中有「資源配置」的
行為,也就是一旦有「配置、釋放」的動作,就讓「配置」成為一個初
始化的動作,如此,釋放動作就變成自動的了(依物件的 scope 決定)。
簡單地說,RAII 就是善用 C++ class 的解構式(destroctor),來達成
資源自動管理的目的。簡單應用如下:
void f() // 一、使用 auto_ptr 避免手動 delete
{
// 假設由於某種原因,TMemoryStream 必須以 new 的方式建立
std::auto_ptr<TMemoryStream> p(new TMemoryStream);
...
if (...) { throw 1; }
...
} // OK, 沒問題,一旦碰到右大括號,即使發生異常,p 也會正確被釋放。
void g() // 二、使用 vector 取代手動配置 array
{
int N;
std::cin >> N;
std::vector<int> v(N);
...
if (...) { throw 1; }
...
} // OK, 沒問題,即使發生異常,也不必操心 v 內部的記憶體管理
std::string g2() // 三、以回傳物件的方式,取代回傳函式內部 new 的物件的指標
{
std::string s;
...
return s;
} // OK, 外部模組不必擔心忘記釋放記憶體的問題。
以上三個例子都很簡單,看起來沒什麼,但這就是 RAII 的基本精神,
再舉個多緒程式的例子,普通是像這樣寫:
void f() // 未考慮「異常安全」的版本
{
...
ThreadLock(...);
... // 在此區域內,不允許兩個執行緒同時進入。
ThreadUnlock(...);
...
};
以上的程式看起來沒問題,但要是在 Lock 和 Unlock 之間,程式發生
異常(而且被上層處理掉了),Unlock 就沒被執行到,就出大事了。因
此,最保險的方法是應用 RAII 的精神,把「鎖定」和「解除」的功能
封裝起來:
struct Lock
{
Lock(...) { ThreadLock(...); }
~Lock() { ThreadUnlock(...); }
...
};
如此,以上的 f 函式就可以改寫如下:
void f2() // RAII 版本
{
...
{
Lock lock(...);
...
} // OK, 不管是否發生異常,lock 物件一旦至此就會被解構。
...
}
著名的 Loki 函式庫中的處理多緒程式的幾個 class,就是用這種
方式設計的。
有些 C++ 編譯器支援類似 Java 或 C# 的 try __finally 的功能,
就是為了解決在複雜程式迴路下,資源配置和釋放的問題。但其實
對 C++ 來說是不需要的,只要善用 RAII 就可以了。只要僅記「資
源配置即初始化」,這個基本原則,解構式就是最自然最方便的自
動化資源管理機制。
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 59.120.214.120