欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解C++?智能指針的刪除器

 更新時(shí)間:2025年05月20日 08:47:40   作者:saltymilk  
標(biāo)準(zhǔn)庫(kù)為智能指針提供了兩個(gè)默認(rèn)版本的刪除器,可簡(jiǎn)化智能指針的代碼編寫(xiě),這篇文章主要介紹了C++智能指針的刪除器的相關(guān)知識(shí),需要的朋友可以參考下

為什么要設(shè)置刪除器

C++11 加入STL的 shared_ptr 和 unique_ptr,已經(jīng)是我們編碼的??土恕S玫亩嘧匀痪蜁?huì)了解到它們的刪除器,比如很多C語(yǔ)言庫(kù)(GDAL, GLFW, libcurl等等)創(chuàng)建的指針不能簡(jiǎn)單的使用 delete 釋放,當(dāng)我們想使用智能指針管理這些庫(kù)創(chuàng)建的資源時(shí),必須設(shè)置刪除器:

//使用重載了operator()的類作為刪除器
struct CurlCleaner
{
  void operator()(CURL *ptr) const
  {
    curl_easy_cleanup(ptr);
  }
};
std::unique_ptr<CURL, CurlCleaner> curlu(curl_easy_init(), CurlCleaner{});//第二個(gè)參數(shù)可省略,因?yàn)镃urlCleaner可默認(rèn)構(gòu)造
std::shared_ptr<CURL> curls(curl_easy_init(), CurlCleaner{});
//使用函數(shù)指針作為刪除器
void GLFWClean(GLFWwindow *wnd)
{
  glfwDestroyWindow(wnd);
}
std::unique_ptr<GLFWwindow, decltype(&GLFWClean)> glfwu(glfwCreateWindow(/*省略*/), GLFWClean);//第二個(gè)參數(shù)必須傳入實(shí)際調(diào)用的函數(shù)地址
std::shared_ptr<GLFWwindow> glfws(glfwCreateWindow(/*省略*/), GLFWClean);
//上述兩個(gè)構(gòu)造函數(shù)中的第二個(gè)參數(shù)都進(jìn)行了函數(shù)名到函數(shù)指針的隱式轉(zhuǎn)換
//使用lambda作為刪除器
auto GDALClean=[](GDALDataset *dataset){ GDALClose(dataset); };
std::unique_ptr<GDALDataset, decltype(GDALClean)> gdalu(GDALOpen(/*省略*/), GDALClean);//lambda無(wú)法默認(rèn)構(gòu)造,必須傳入一個(gè)實(shí)例
std::shared_ptr<GDALDataset> gdals(GDALOpen(/*省略*/), GDALClean);

上面是三種最常使用的自定義刪除器形式,也可以利用 std::function 的強(qiáng)大適配能力來(lái)包裝可調(diào)用對(duì)象作為刪除器,此處不展開(kāi)。

標(biāo)準(zhǔn)庫(kù)提供的默認(rèn)刪除器

內(nèi)置類型和析構(gòu)函數(shù)為 public 的類類型,無(wú)需指定刪除器,智能指針會(huì)在引用計(jì)數(shù)歸零時(shí)自動(dòng)調(diào)用 delete 對(duì)管理的指針進(jìn)行釋放,使得語(yǔ)法相對(duì)簡(jiǎn)潔:

std::unique_ptr<int> pi(new int(42));
std::shared_ptr<float> pf(new float(0.0f));
std::unique_ptr<std::vector<int>> pveci(new std::vector<int>());
std::unique_ptr<std::list<int>> plsti(new std::list<int>());

很長(zhǎng)一段時(shí)間內(nèi),我以為智能指針只有 delete 一個(gè)默認(rèn)的刪除器,所以每次在管理 new[] 得到的指針時(shí),都會(huì)為它編寫(xiě)調(diào)用 delete[] 的刪除器,直到翻看智能指針的源碼,發(fā)現(xiàn)它們的默認(rèn)刪除器其實(shí)有一個(gè)針對(duì)數(shù)組形式指針的特化版本:

template<class _Tp>
struct default_delete//默認(rèn)刪除器主模板
{
  ...
  void operator()(_Tp *_Ptr) const noexcept
  {
    ...
    delete _Ptr;//使用delete釋放指針
  }
  ...
}
template<class _Tp>
struct default_delete<_Tp[]>//針對(duì)數(shù)組形式的特化版本
{
  ...
  void operator()(_Tp *_Ptr) const noexcept
  {
    ...
    delete[] _Ptr;//使用delete[]釋放指針
  }
  ...
}
//unique_ptr
template<class _Tp, class _Dp = default_delete<_Tp>/*默認(rèn)刪除器*/>
class unique_ptr{...};
//shared_ptr
template <class, class _Yp>//輔助類主模板,普通指針應(yīng)用該版本
struct __shared_ptr_default_delete : default_delete<_Yp> {};
template <class _Yp, class _Un, size_t _Sz>//數(shù)組形式特化,匹配固定長(zhǎng)度的數(shù)組形式,如std::shared_ptr<int[10]>
struct __shared_ptr_default_delete<_Yp[_Sz], _Un> : default_delete<_Yp[]> {};
template <class _Yp, class _Un>//數(shù)組形式特化,匹配不定長(zhǎng)度的數(shù)組形式,如std::shared_ptr<int[]>
struct __shared_ptr_default_delete<_Yp[], _Un> : default_delete<_Yp[]> {};
template<class _Tp>
class shared_ptr
{
  ...
  template <class _Yp,/*檢查_(kāi)Yp指針是否可轉(zhuǎn)換為_(kāi)Tp指針(比如子類指針到基類指針)、_Yp類型是否可應(yīng)用delete與delete[]操作*/>
  explicit shared_ptr(_Yp* __p) : __ptr_(__p) {
    ...
    typedef __shared_ptr_pointer<_Yp*, __shared_ptr_default_delete<_Tp, _Yp>/*根據(jù)_Yp類型選擇合適的默認(rèn)刪除器*/, _AllocT> _CntrlBlk;
    __cntrl_ = new _CntrlBlk(__p, __shared_ptr_default_delete<_Tp, _Yp>(), _AllocT());
    ...
  }
  ...
};
//用戶代碼
std::unique_ptr<int[]> piu(new int[10]);//匹配int[]版本,刪除器編譯為使用delete[]釋放指針
std::shared_ptr<int[]> pis(new int[10]);//構(gòu)造函數(shù)內(nèi)選擇使用delete[]釋放指針的刪除器

以上代碼節(jié)選自 llvm-mingw 的標(biāo)準(zhǔn)庫(kù),查看了一下手頭上的幾個(gè)版本的標(biāo)準(zhǔn)庫(kù)實(shí)現(xiàn),發(fā)現(xiàn) unique_ptr 的實(shí)現(xiàn)大致類似。值得一提的是,unique_ptr 自身也有針對(duì)數(shù)組形式的特化版本 unique_ptr<_Tp[]>,由于知曉管理的是數(shù)組形式的指針,這個(gè)特化版本不提供 operator-> 訪問(wèn)符號(hào),取而代之的是 operator[] 來(lái)訪問(wèn)數(shù)組數(shù)據(jù)。

llvm-mingw shared_ptr 默認(rèn)刪除器的選擇是通過(guò)輔助模板類 __shared_ptr_default_delete 的特化來(lái)實(shí)現(xiàn)的;MSVC 版本中 shared_ptr 的構(gòu)造函數(shù)則直接使用 if consexpr(雖然是 C++17 開(kāi)始支持,但是發(fā)現(xiàn) C++14 版本的代碼中已經(jīng)使用)判斷實(shí)例化指針類型是否為數(shù)組形式選擇相應(yīng)刪除器;GCC 的 shared_ptr 邏輯相對(duì)復(fù)雜一些,其 shared_ptr 繼承自 __shared_ptr,而 __shared_ptr 有一個(gè)類型為 __shared_count 的成員 _M_refcount, 該類有一系列重載的構(gòu)造函數(shù),其中幾個(gè)是:

struct __sp_array_delete
{
  template<typename _Yp>
  void operator()(_Yp *__p) const 
  {
    delete[] __p;
  }
};
r1: template<typename _Ptr>/*默認(rèn)使用delete版本的刪除器,省略實(shí)現(xiàn)*/
    explicit __shared_count(_Ptr __p)
r2: template<typename _Ptr>/*委托給r1*/
    __shared_count(_Ptr __P, false_type) : __shared_count(__p){}
r3: template<typename _Ptr, typename _Deleter, typename _Alloc, typename = typename __not_alloc_shared_tag<_Deleter>::type>
    __shared_count(_Ptr __p, _Deleter __d, _Alloc __a)/*可指定刪除器、內(nèi)存分配器的版本*/
r4: template<typename _Ptr>/*委托給r3*/
    __shared_count(_Ptr __p, true_type) : __shared_count(__p, __sp_array_delete{}, allocator<void>()){}
//__shared_ptr的接受一個(gè)指針參數(shù)的構(gòu)造函數(shù)
template<typename _Yp, /*檢查_(kāi)Yp *是否和轉(zhuǎn)換為類的實(shí)例化指針類型*/>
explicit __shared_ptr(_Yp *__p): _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type()){...}

通過(guò)代碼我們大致可以推測(cè),__shared_count 這個(gè)類是用來(lái)管理引用計(jì)數(shù)和刪除器的類。
可以看到,如果 __shared_ptr 構(gòu)造函數(shù)接受的指針類型為普通指針,會(huì)調(diào)用 __shared_count(__p, false_type) 將 _M_refcount 構(gòu)造為使用 delete 釋放指針的版本;而當(dāng)它接受的指針類型為數(shù)組形式指針時(shí),__shared_count(__p, true_type) 則會(huì)被調(diào)用,構(gòu)造的 _M_refcount 存儲(chǔ)的刪除器是 __sp_array_delete 類型,這個(gè)類型使用 delete[] 釋放指針。

總結(jié)

1.銷毀前需要額外資源釋放操作的類型,使用智能指針管理時(shí)必須設(shè)置自定義刪除器
2.標(biāo)準(zhǔn)庫(kù)為智能指針提供了兩個(gè)默認(rèn)版本的刪除器,可簡(jiǎn)化智能指針的代碼編寫(xiě)

到此這篇關(guān)于C++ 智能指針的刪除器的文章就介紹到這了,更多相關(guān)C++ 智能指針內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語(yǔ)言實(shí)現(xiàn)個(gè)人財(cái)務(wù)管理軟件

    C語(yǔ)言實(shí)現(xiàn)個(gè)人財(cái)務(wù)管理軟件

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)個(gè)人財(cái)務(wù)管理軟件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • VC基于ADO技術(shù)訪問(wèn)數(shù)據(jù)庫(kù)的方法

    VC基于ADO技術(shù)訪問(wèn)數(shù)據(jù)庫(kù)的方法

    這篇文章主要介紹了VC基于ADO技術(shù)訪問(wèn)數(shù)據(jù)庫(kù)的方法,較為詳細(xì)的分析了VC使用ADO操作數(shù)據(jù)庫(kù)的相關(guān)實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-10-10
  • C++ 程序員為什么看不起php程序員

    C++ 程序員為什么看不起php程序員

    由于當(dāng)今市場(chǎng)狀況,各種培訓(xùn)班飛起,PHPer越來(lái)越多,學(xué)習(xí)成本很低。導(dǎo)致了很多人對(duì)PHP的誤解。其實(shí)PHP學(xué)到深入的時(shí)候,所需知識(shí)很多,并不是表面看到的那樣。另外,PHP確實(shí)嚴(yán)謹(jǐn)性不高,這個(gè)跟C++,java確實(shí)都沒(méi)法比。但是,PHP在web開(kāi)發(fā)中的效率,是其他語(yǔ)言所不能比的
    2017-02-02
  • c語(yǔ)言判斷是否素?cái)?shù)程序代碼

    c語(yǔ)言判斷是否素?cái)?shù)程序代碼

    這篇文章主要介紹了c語(yǔ)言判斷是否素?cái)?shù)的方法和問(wèn)題,大家參考使用吧
    2013-11-11
  • C++超詳細(xì)講解友元的使用

    C++超詳細(xì)講解友元的使用

    采用類的機(jī)制后實(shí)現(xiàn)了數(shù)據(jù)的隱藏與封裝,類的數(shù)據(jù)成員一般定義為私有成員,成員函數(shù)一般定義為公有的,依此提供類與外界間的通信接口。但是,有時(shí)需要定義一些函數(shù),這些函數(shù)不是類的一部分,但又需要頻繁地訪問(wèn)類的數(shù)據(jù)成員,這時(shí)可以將這些函數(shù)定義為該類的友元函數(shù)
    2022-04-04
  • Qt Creator使用教程的簡(jiǎn)單說(shuō)明

    Qt Creator使用教程的簡(jiǎn)單說(shuō)明

    如今 Qt Creator 功能十分強(qiáng)大了,包含項(xiàng)目模板生成、代碼編輯、UI 設(shè)計(jì)、QML 界面編輯、調(diào)試程序、上下文幫助等豐富功能,本文就詳細(xì)的介紹一下如何使用
    2021-08-08
  • C語(yǔ)言單值二叉樹(shù)真題講解

    C語(yǔ)言單值二叉樹(shù)真題講解

    單值二叉樹(shù)你可能之前沒(méi)見(jiàn)過(guò),如果二叉樹(shù)每個(gè)節(jié)點(diǎn)都具有相同的值,那么該二叉樹(shù)就是單值二叉樹(shù),讓我們通過(guò)一個(gè)真題來(lái)深刻了解它吧
    2022-04-04
  • C語(yǔ)言編程中建立和解除內(nèi)存映射的方法

    C語(yǔ)言編程中建立和解除內(nèi)存映射的方法

    這篇文章主要介紹了C語(yǔ)言編程中建立和解除內(nèi)存映射的方法,分別為mmap()函數(shù)和munmap()函數(shù)的使用,需要的朋友可以參考下
    2015-08-08
  • C++使用ffmpeg實(shí)現(xiàn)rtsp取流的代碼

    C++使用ffmpeg實(shí)現(xiàn)rtsp取流的代碼

    這篇文章主要介紹了C++使用ffmpeg實(shí)現(xiàn)rtsp取流,文章介紹了ffmepg采用rtsp取流流程圖,CMakeLists.txt編寫(xiě)方法,通過(guò)示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單掃雷小程序

    C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單掃雷小程序

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單掃雷小程序,一款大眾類的益智小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10

最新評(píng)論