想要搶先看後面的章節?打賞本文10元,即可獲得帶插圖全本下載地址!打賞完成記得私信我哦 :p

12.2.5 對shared_ptr的釋放行為進行自定義

有時候,使用shared_ptr管理某些特別的資源時,它們的釋放不是簡單地使用delete操作符釋放內存資源就可以完成的,還有可能需要一些額外的清理工作。在這種情況下,就需要對shared_ptr的釋放行為進行自定義以完成特殊的釋放清理工作。

shared_ptr所管理的資源的釋放工作都是由它的刪除器(deleter)來完成的。shared_ptr提供了一個可以接收某個函數指針(或函數對象)為參數的特殊的構造函數,通過這個構造函數,我們可以指定這個函數作為shared_ptr的刪除器,從而讓我們有機會通過這個函數對shared_ptr的釋放工作進行自定義:

// shared_ptr帶刪除器參數的構造函數
template<class Other, class D> shared_ptr(Other * ptr, D dtor);

其中,第一個參數指向shared_ptr將要對其進行管理的某個資源(這裡不再僅僅是內存資源,也有可能是程序中的其他共享資源,比如某個文件);第二個參數則是負責釋放這個資源的函數,也被稱為shared_ptr的刪除器。當shared_ptr所管理資源的引用計數變為0時,它就會以指向這個資源的指針作為參數來調用這個函數,以此來完成資源的釋放清理工作。這對於shared_ptr管理那些不是用new申請也不是用delete釋放的非內存資源時非常有用。例如,我們需要在程序的多個過程中共享某個日誌文件,而這個文件又沒有一個明確的所有者,為了保證文件在最後能夠被正確關閉,我們決定用shared_ptr來管理這個文件資源:

#include <fstream>
#include <memory>

using namespace std;
// 負責shared_ptr釋放工作的函數
// 其參數類型為指向shared_ptr所管理資源的指針
void CloseFile(ofstream* pLogFile)
{
// 完成額外的清理工作
(*pLogFile)<<"日誌文件結束"<<endl; // 輸出文件結束信息
pLogFile->close(); // 關閉文件
delete pLogFile; // 釋放內存資源
}
// 某個需要記錄日誌的函數
void foo(shared_ptr<ofstream> spLogFile)
{
// 通過shared_ptr管理的文件輸出日誌
(*spLogFile)<<"foo()函數被調用"<<endl;
}

int main()
{
// 創建一個日誌文件並交由shared_ptr進行管理
// 同時指定這個資源的釋放工作由CloseFile()函數完成
shared_ptr<ofstream> spLogFile(new ofstream("log.txt"),CloseFile);
// 通過shard_ptr訪問它所管理的日誌文件以記錄日誌
(*spLogFile)<<"main()函數被調用"<<endl;
// 將shared_ptr傳遞給foo()函數供其記錄日誌
foo(spLogFile);

return 0; // 到這裡,所有指向日誌文件的shared_ptr都結束其生命週期,
// 日誌文件的引用計數變為0,CloseFile()函數被調用以完成釋放工作
}

在這段代碼中,我們在創建shared_ptr對ofstream對象進行管理的同時,提供一個CloseFile()函數作為其刪除器。當ofstream對象的引用計數變為0時,shared_ptr就會以指向這個ofstream對象的指針為參數調用這個函數來完成資源的釋放工作。這裡對ofstream對象的釋放,不僅僅是用delete操作符釋放內存資源,在這之前,我們還向日誌文件中輸出了表示日誌文件結束的信息,然後使用它的close()成員函數關閉了日誌文件,最後纔是用delete操作符釋放內存。

通過對shared_ptr釋放行為的自定義,使得它可以用於管理程序中任何的共享資源,比如內存資源、文件或者網路連接等。與通過普通指針在多個過程中共享資源相比,shared_ptr是會有那麼一點點空間和性能上的損失,但是跟它所帶來的共享資源的安全釋放相比,這一點點的損失就微不足道了。當我們的程序比較複雜,而我們又需要在程序的多個過程之間共享資源,且這些共享資源又沒有一個明確的所有者的時候,用shared_ptr來對共享資源進行管理是一個性價比很高的解決方案。

推薦閱讀:

相關文章