*以下內容為本人的學習筆記,如需要轉載,請宣告原文鏈接 微信公眾號「ENG八戒」https://mp.weixin.qq.com/s/7A9-tGZxf4w_7eZl3OUQ4A

學過 Java、C# 或者其他托管語言(managed languages)的同學,回過頭來看 C++ 的時候,第一反應就是 C++ 沒有自動垃圾回收器(GC),而不能充分利用的資源被稱為垃圾,
那么 C++ 真的不能自動回收垃圾嗎?帶著這個疑問我們來看看一般 C++ 程式都是怎樣回收資源的,
記憶體在計算機系統中是有限的資源,通常申請記憶體和釋放記憶體是這樣子的,假設有個被呼叫的函式 function():
void function()
{
int *p = new int; // 申請記憶體
// 資源申請下來了,不玩有個 p 用?
// do something
delete p; // 釋放記憶體
}
這段示例代碼在 function() 函式開始的時候申請了一塊記憶體,大小對應于 int 型別,然后在函式結束的時候釋放它,通常來說,這看起來很OK,沒毛病,但是,如果遇到了下面幾種情況呢?
- 程式如果中途有邏輯讓它提前退出 function() 函式
- 發生了例外而沒有被捕獲到
那么在函式尾部執行釋放記憶體的動作有幾率不會被執行,意味著發生也會記憶體泄漏,像上面這段代碼,如果呼叫的次數不多也不礙事,不過,如果回圈呼叫 function(),這時泄露的記憶體資源會不斷累積,而且一直被浪費掉,期間系統無法再次使用這些被浪費的記憶體,直到行程被終止,嚴重的話,會導致系統資源被耗盡,跑著跑著系統都崩潰了,這種 bug 在 C 范式的編程語言中真的很常見,
RAII 是什么
眾所周知 C++ 具有面向物件的特性,在初始化類物件的時候,系統會呼叫類建構式,如果類物件是存放在堆疊空間的話,比如宣告為區域變數,那么當類物件超出生命周期時,比如退出區域變數的作用域,系統會呼叫這個物件的類解構式;如果類物件是存放在堆空間的話,比如通過 new 運算子創建的類物件,那么當類物件被銷毀時,比如對物件執行 delete 操作,系統同樣會呼叫類解構式,
C++ 的這個特性可以用來解決上面提到的資源泄露問題,怎么利用呢?
modern C++ 實踐建議優先把資源存放在堆疊上,如果只是個變數型別,完全可以用區域變數的形式定義宣告,這樣代碼塊在退出后系統自動回收堆疊上的資源,
對上面的函式 function() 修改
void function()
{
// 宣告定義為區域變數,資源存盤在堆疊區
int data = https://www.cnblogs.com/englyf/archive/2023/05/18/0;
// do something with data
// 函式退出時,自動釋放 data 占用的空間
}
當資源比較占空間時,需要在堆上分配資源,可以通過指標參考它,資源的申請放在類的建構式里,然后在解構式里釋放,下面舉個例子
class Helper
{
private:
int* data;
public:
Helper() {
data = https://www.cnblogs.com/englyf/archive/2023/05/18/new int; // 在堆上申請記憶體
}
~Helper() {
delete data; // 釋放堆上申請的記憶體
}
void do_something_with_data() {}
};
void function()
{
// 宣告定義為區域變數,物件存盤在堆疊區
// 呼叫 Helper 類建構式在堆上申請資源
Helper help;
// 通過物件 help 呼叫成員 data
// 如果 data 是 Helper 私有成員
// 在類外面必須通過類成員方法呼叫 data
help.do_something_with_data();
// 函式退出時,自動釋放 help 物件占用的堆疊空間
// 就算發生了例外或者中途退出都會執行這一步
// help 物件被銷毀時,呼叫 Helper 類解構式
// Helper 類解構式釋放已申請的堆上資源
}
利用這種特性的行為被 C++ 發明人稱呼為 RAII,英文全稱是「resource acquisition is initialization」,中文翻譯過來是「資源獲取即是初始化」,而我喜歡把它叫做背景關系管理,實作資源申請釋放的類叫做背景關系管理器(context manager),
經典實踐--智能指標
上面的示例代碼寫起來略顯啰嗦,為了推廣這種設計核心思路和簡化代碼撰寫,在 C++ 11 之后標準庫里添加了 unique_ptr,
unique_ptr 屬于 Smart Points 中的一種,Smart Points 在國內通常翻譯為「智能指標」,智能指標負責管理和釋放資源,上面的 function() 函式可以改成這樣子
#include <memory>
void function()
{
// 實體化智能指標物件,輸入需要被管理的記憶體首地址
// 物件為區域變數,存盤在堆疊區
std::unique_ptr<int> data(new int);
// 智能指標物件就像普通指標一樣呼叫
printf("data=https://www.cnblogs.com/englyf/archive/2023/05/18/%d/n", *data);
// 函式退出時,自動釋放 data 物件占用的堆疊空間
// 就算發生了例外或者中途退出都會執行這一步
// data 物件被銷毀時,同步釋放被管理的記憶體資源
}
可見,用了智能指標后,不需要像之前那樣定義類 Helper (背景關系管理器)了,代碼清爽很多,
不過,上面的示例代碼中有個地方需要注意,在實體化智能指標物件時必須傳入記憶體地址,有沒有其它更好的方式設定被管理的記憶體地址?
有的,C++ 14 之后標準庫添加了 make_unique,演示一下怎么用
std::unique_ptr<int> data = https://www.cnblogs.com/englyf/archive/2023/05/18/std::make_unique();
薦書活動
編程的設計思想是一門很有意思的事情,其中有一門前人總結得很到位的學問叫「設計模式」,想深入了解嗎?
最近在聯合機械工業出版社搞薦書活動,這次參與活動的圖書是《深入理解設計模式》,作者是林祥纖,

其中有幾本樣書,八戒 想送給讀者朋友,需要免費領取圖書的朋友可以點擊文章抬頭的原文鏈接!
圖書簡介:
本書以作者與虛擬女友(小璐)在生活中遇到的各種問題作為主線,引出設計模式的各種功能、用途,以及解決方法,系統介紹了23種設計模式,根據具體的實體形象化、具體化地進行了代碼的撰寫和詳細講解,讓那些本來對設計模式不太了解、一知半解、只有概念的讀者,徹底了解和掌握常用的設計模式使用場景及使用方式,并掌握每個設計模式的UML結構和描繪方式,
本書共23章,包括認識設計模式、單例模式、工廠模式、建造者模式、原型模式、配接器模式、裝飾器模式、外觀模式、橋接模式、組合模式、享元模式、代理模式、策略模式、命令模式、狀態模式、模板方法模式、備忘錄模式、中介者模式、觀察者模式、迭代器模式、責任鏈模式、訪問者模式、解釋器模式,
通過以上的知識,讓你從模式小白直接升級為模式大神!本書所需源代碼,均可通過本書配套下載鏈接獲得, 本書適合編程初學者或希望在面向物件編程上有所提高的開發人員閱讀,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/552681.html
標籤:其他
上一篇:Spring Cloud開發實踐(五): Consul - 服務注冊的另一個選擇
下一篇:返回列表
