最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

為什么要設置刪除器

C++11 加入STL的 shared_ptr 和 unique_ptr,已經(jīng)是我們編碼的??土?。用的多自然就會了解到它們的刪除器,比如很多C語言庫(GDAL, GLFW, libcurl等等)創(chuàng)建的指針不能簡單的使用 delete 釋放,當我們想使用智能指針管理這些庫創(chuàng)建的資源時,必須設置刪除器:

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

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

標準庫提供的默認刪除器

內(nèi)置類型和析構函數(shù)為 public 的類類型,無需指定刪除器,智能指針會在引用計數(shù)歸零時自動調(diào)用 delete 對管理的指針進行釋放,使得語法相對簡潔:

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 一個默認的刪除器,所以每次在管理 new[] 得到的指針時,都會為它編寫調(diào)用 delete[] 的刪除器,直到翻看智能指針的源碼,發(fā)現(xiàn)它們的默認刪除器其實有一個針對數(shù)組形式指針的特化版本:

template<class _Tp>
struct default_delete//默認刪除器主模板
{
  ...
  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>/*默認刪除器*/>
class unique_ptr{...};
//shared_ptr
template <class, class _Yp>//輔助類主模板,普通指針應用該版本
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指針是否可轉換為_Tp指針(比如子類指針到基類指針)、_Yp類型是否可應用delete與delete[]操作*/>
  explicit shared_ptr(_Yp* __p) : __ptr_(__p) {
    ...
    typedef __shared_ptr_pointer<_Yp*, __shared_ptr_default_delete<_Tp, _Yp>/*根據(jù)_Yp類型選擇合適的默認刪除器*/, _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]);//構造函數(shù)內(nèi)選擇使用delete[]釋放指針的刪除器

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

struct __sp_array_delete
{
  template<typename _Yp>
  void operator()(_Yp *__p) const 
  {
    delete[] __p;
  }
};
r1: template<typename _Ptr>/*默認使用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ù)的構造函數(shù)
template<typename _Yp, /*檢查_Yp *是否和轉換為類的實例化指針類型*/>
explicit __shared_ptr(_Yp *__p): _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type()){...}

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

總結

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

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

相關文章

  • C++?STL標準庫std::vector擴容時進行深復制原因詳解

    C++?STL標準庫std::vector擴容時進行深復制原因詳解

    我們知道,std::vector之所以可以動態(tài)擴容,同時還可以保持順序存儲,主要取決于其擴容復制的機制。當容量滿時,會重新劃分一片更大的內(nèi)存區(qū)域,然后將所有的元素拷貝過去
    2022-08-08
  • C++超詳細分析順序表

    C++超詳細分析順序表

    程序中經(jīng)常需要將一組數(shù)據(jù)元素作為整體管理和使用,需要創(chuàng)建這種元素組,用變量記錄它們,傳進傳出函數(shù)等。一組數(shù)據(jù)中包含的元素個數(shù)可能發(fā)生變化,順序表則是將元素順序地存放在一塊連續(xù)的存儲區(qū)里,元素間的順序關系由它們的存儲順序自然表示
    2022-03-03
  • 詳談浮點精度(float、double)運算不精確的原因

    詳談浮點精度(float、double)運算不精確的原因

    這篇文章主要介紹了詳談浮點精度(float、double)運算不精確的原因,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • C語言全方位講解指針與地址和數(shù)組函數(shù)堆空間的關系

    C語言全方位講解指針與地址和數(shù)組函數(shù)堆空間的關系

    指針是C語言中一個非常重要的概念,也是C語言的特色之一。使用指針可以對復雜數(shù)據(jù)進行處理,能對計算機的內(nèi)存分配進行控制,在函數(shù)調(diào)用中使用指針還可以返回多個值
    2022-04-04
  • C++實現(xiàn)順序排序算法簡單示例代碼

    C++實現(xiàn)順序排序算法簡單示例代碼

    這篇文章主要介紹了C++實現(xiàn)順序排序算法簡單示例代碼,對于學過C++的朋友一定不會陌生,現(xiàn)在重溫一下這個算法,需要的朋友可以參考下
    2014-08-08
  • C語言實現(xiàn)三子棋游戲簡易版

    C語言實現(xiàn)三子棋游戲簡易版

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)三子棋游戲簡易版,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • HDOJ 1443 約瑟夫環(huán)的最新應用分析詳解

    HDOJ 1443 約瑟夫環(huán)的最新應用分析詳解

    本篇文章是對HDOJ 1443 約瑟夫環(huán)的最新應用進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • 深入了解C++異常處理

    深入了解C++異常處理

    任何東西都可以認為是異常,錯誤只是異常的一種。本文將帶大家了解C++中異常是什么,是如何捕獲和處理的等相關知識。文中示例代碼簡潔易懂,感興趣的小伙伴可以了解一下
    2021-12-12
  • json error: Use of overloaded operator [] is ambiguous錯誤的解決方法

    json error: Use of overloaded operator [] is ambiguous錯誤的解決方

    今天小編就為大家分享一篇關于json error: Use of overloaded operator [] is ambiguous錯誤的解決方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-04-04
  • C++日志庫log4cplus的使用詳解

    C++日志庫log4cplus的使用詳解

    C++實現(xiàn)的log4cplus日志庫是一種易于使用的C?++日志記錄API,可提供線程安全,靈活且任意粒度的日志管理和配置控制。這篇文章就來和大家講講log4cplus的使用吧
    2023-03-03

最新評論

呼玛县| 嘉善县| 麻栗坡县| 中方县| 历史| 康保县| 临西县| 神池县| 淮南市| 陆河县| 汝州市| 嘉峪关市| 星子县| 台前县| 阳信县| 台江县| 栾川县| 宝山区| 麦盖提县| 黑山县| 道孚县| 满洲里市| 盐亭县| 宜黄县| 金平| 泰兴市| 揭东县| 东海县| 远安县| 祁连县| 藁城市| 新余市| 泌阳县| 宣威市| 久治县| 叶城县| 潜山县| 汝南县| 公安县| 常宁市| 滁州市|