亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

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

C++11 加入STL的 shared_ptr 和 unique_ptr,已經(jīng)是我們編碼的??土恕S玫亩嘧匀痪蜁私獾剿鼈兊膭h除器,比如很多C語言庫(GDAL, GLFW, libcurl等等)創(chuàng)建的指針不能簡單的使用 delete 釋放,當(dāng)我們想使用智能指針管理這些庫創(chuàng)建的資源時,必須設(shè)置刪除器:

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

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

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

內(nèi)置類型和析構(gòu)函數(shù)為 public 的類類型,無需指定刪除器,智能指針會在引用計數(shù)歸零時自動調(diào)用 delete 對管理的指針進(jì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>());

很長一段時間內(nèi),我以為智能指針只有 delete 一個默認(rèn)的刪除器,所以每次在管理 new[] 得到的指針時,都會為它編寫調(diào)用 delete[] 的刪除器,直到翻看智能指針的源碼,發(fā)現(xiàn)它們的默認(rèn)刪除器其實有一個針對數(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[]>//針對數(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ù)組形式特化,匹配固定長度的數(shù)組形式,如std::shared_ptr<int[10]>
struct __shared_ptr_default_delete<_Yp[_Sz], _Un> : default_delete<_Yp[]> {};
template <class _Yp, class _Un>//數(shù)組形式特化,匹配不定長度的數(shù)組形式,如std::shared_ptr<int[]>
struct __shared_ptr_default_delete<_Yp[], _Un> : default_delete<_Yp[]> {};
template<class _Tp>
class shared_ptr
{
  ...
  template <class _Yp,/*檢查_Yp指針是否可轉(zhuǎn)換為_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)庫,查看了一下手頭上的幾個版本的標(biāo)準(zhǔn)庫實現(xiàn),發(fā)現(xiàn) unique_ptr 的實現(xiàn)大致類似。值得一提的是,unique_ptr 自身也有針對數(shù)組形式的特化版本 unique_ptr<_Tp[]>,由于知曉管理的是數(shù)組形式的指針,這個特化版本不提供 operator-> 訪問符號,取而代之的是 operator[] 來訪問數(shù)組數(shù)據(jù)。

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

struct __sp_array_delete
{
  template<typename _Yp>
  void operator()(_Yp *__p) const 
  {
    delete[] __p;
  }
};
r1: template<typename _Ptr>/*默認(rèn)使用delete版本的刪除器,省略實現(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的接受一個指針參數(shù)的構(gòu)造函數(shù)
template<typename _Yp, /*檢查_Yp *是否和轉(zhuǎn)換為類的實例化指針類型*/>
explicit __shared_ptr(_Yp *__p): _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type()){...}

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

總結(jié)

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

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

相關(guān)文章

  • C語言實現(xiàn)個人財務(wù)管理軟件

    C語言實現(xiàn)個人財務(wù)管理軟件

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

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

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

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

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

    c語言判斷是否素數(shù)程序代碼

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

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

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

    Qt Creator使用教程的簡單說明

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

    C語言單值二叉樹真題講解

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

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

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

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

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

    C語言實現(xiàn)簡單掃雷小程序

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

最新評論