轉自:雨樂聊編程
我們以經常用到的std::shared_ptr為例,在面試候選人的時候,我也會問相關問題,很多人都會提到引用計數為0的時候會自動釋放該指針所關聯的內存資源:
int main() {
std::shared_ptr<int> p = std::make_shared<int>();
}也就是說在智能指針p離開main函數作用域的時候會自動釋放資源,這種實現技術,就是我們本文要講的RAII。
RAII即Resource Acquisition Is Initialization的縮寫,如果用中午來翻譯則是資源獲取即初始化?,F代 C++ 編程中的一個非常重要的概念,它確保了資源管理既安全又高效,同時也很直觀,其核心思想是將必須顯式獲取和釋放的資源的生命周期與對象的生命周期綁定在一起。這個概念在編寫穩健的 C++ 應用程序時特別重要,尤其是當你需要處理像內存、文件句柄、網絡連接這些需要手動釋放的資源時。
當一個對象被創建時,它會獲取某些資源(比如打開文件、分配內存等);而當對象超出作用域時,它的析構函數會自動被調用,從而釋放這些資源。這種方法有助于防止資源泄漏,確保程序的異常安全,同時使代碼更加易讀和易維護。
在C++中,RAII 使用構造函數和析構函數實現。構造函數獲取資源,相應的析構函數釋放資源。
下面,我們從幾個例子來聊聊RAII的用法。
讓我們考慮一個類似的例子,其中一個資源是動態分配的,但是函數中有幾個路徑可能會導致資源無法正確釋放,從而導致內存泄漏。
struct Resource {
int x_;
int y_;
Resource(int x, int y) : x_(x), y_(y) {}
}
void fun(bool flag) {
auto &&ptr = newResource(1, 2);
if (!flag) {
return;
}
// do sth
delete ptr;
}在這個代碼中:
? 通過new方式創建一個Resource指針,并將其賦值給ptr
? 該函數參數為一個bool類型
? 如果用戶輸入參數為false,則直接返回
? 如果輸入參數為true,則繼續后面的邏輯,到最后通過delete方式釋放資源
這段代碼,很明顯存在內存泄漏,如果想要避免的,可以使用我們前面提到的std::shared_ptr:
struct Resource {
int x_;
int y_;
Resource(int x, int y) : x_(x), y_(y) {}
}
void fun(bool flag) {
auto &&ptr = std::make_shared<Resource>(1, 2);
if (!flag) {
return;
}
// do sth
}原理也是比較簡單,不再贅述~
從這個例子可以看出,如果 不使用RAII,而單純人為去釋放資源,難免會有遺漏之處,如果此函數調用頻繁,泄漏會很嚴重~
下面是一個使用了RAII(基于對象本身)的例子:
class MyArray {
public :
MyArray ( size_t size ) : data ( new int [size] ) {}
~ MyArray () { delete [] data_; }
private :
int * data_;
}這個例子,算是一個非常非常常用的基于RAII的例子,在這個例子中,我們在構造函數中申請資源,在析構函數中釋放資源。當MyArray對象超出其作用域時候,會自動調用析構函數,進而釋放資源。
除了管理我們通常所說的內存外,也可以用來socket。
class Socket {
public:
Socket(int domain, int type, int protocol) {
sockfd = socket(domain, type, protocol);
if (sockfd == -1) {
std::cerr << "Socket creation failed!" << std::endl;
} else {
std::cout << "Socket created successfully!" << std::endl;
}
}
~Socket() {
if (sockfd != -1) {
close(sockfd); // 關閉 socket
std::cout << "Socket closed!" << std::endl;
}
}
private:
int sockfd = -1; // socket 文件描述符
};在這個示例中,構造函數創建一個socket,在析構函數中關閉此描述符。當Socket對象退出 作用域時候,自動調用析構函數,進而關閉描述符。
下面是一個創建臨時文件的類:
class TempFile {
public:
TempFile(const std::string& name) : filename(name) {
std::ofstream temp(filename_);
temp << "Temporary content";
}
~TempFile() {
std::remove(filename_.c_str());
}
private:
std::string filename_;
};在這個例子中,我們使用 RAII(資源獲取即初始化)來管理一個臨時文件。TempFile 類會在其構造函數中創建一個臨時文件,并向其中寫入一些內容;當 TempFile 對象的生命周期結束時,它的析構函數會自動刪除該文件。這樣,即使程序結束或者發生異常,臨時文件也會被正確地刪除,不會留下任何多余的文件。
RAII(資源獲取即初始化)是 C++ 中一個強大的概念,它簡化了資源管理,防止內存泄漏,并確保程序的異常安全。通過將資源管理與對象的生命周期綁定,RAII 使得代碼更加直觀且不容易出錯。作為一種最佳實踐,我們應當在設計中充分利用 RAII,借助語言的構造函數和析構函數來高效地管理資源。
C++ 校招 / 社招跳槽逆襲!從0到1打造高含金量項目,導師1v1輔導,助你斬獲大廠offer!
很多同學準備校招時最焦慮的問題就是:“簡歷沒項目,怎么打動面試官?”
為了解決這個痛點,我們推出了 C++訓練營,來了!

在這里,你可以:
我們不只是教你寫代碼,更帶你走一遍完整的項目流程: 從需求分析、架構設計、編譯調試,到版本管理、測試發布,全流程掌握!
項目配套資料齊全,遇到問題還有導師幫你答疑,不怕卡殼!
項目準備好了,你只差一次出發。
相信我,這些項目絕對能夠讓你進步巨大!下面是其中某三個項目的說明文檔

訓練營適用人群:
不適合人群:

1、C++訓練營,來了!
2、HarmonyOS 學習資料分享(無套路免費分享)
我組建了一些社群一起交流,群里有大牛也有小白,如果你有意可以一起進群交流。
歡迎你添加我的微信,我拉你進技術交流群。此外,我也會經常在微信上分享一些計算機學習經驗以及工作體驗,還有一些內推機會。
加個微信,打開另一扇窗
感謝你的分享,點贊,在看三連