溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么深度剖析C++對象池自動回收技術(shù)實現(xiàn)

發(fā)布時間:2021-11-24 14:05:23 來源:億速云 閱讀:162 作者:柒染 欄目:編程語言

本篇文章為大家展示了怎么深度剖析C++對象池自動回收技術(shù)實現(xiàn),內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。

對象池可以顯著提高性能,如果一個對象的創(chuàng)建非常耗時或非常昂貴,頻繁去創(chuàng)建的話會非常低效。對象池通過對象復(fù)用的方式來避免重復(fù)創(chuàng)建對象,它會事 先創(chuàng)建一定數(shù)量的對象放到池中,當(dāng)用戶需要創(chuàng)建對象的時候,直接從對象池中獲取即可,用完對象之后再放回到對象池中,以便復(fù)用。這種方式避免了重復(fù)創(chuàng)建耗 時或耗資源的大對象,大幅提高了程序性能。小編將探討對象池的技術(shù)特性以及源碼實現(xiàn)。

怎么深度剖析C++對象池自動回收技術(shù)實現(xiàn)

對象池類圖

  • ObjectPool:管理對象實例的pool。

  • Client:使用者。

適用性:

  • 類的實例可重用。

  • 類的實例化過程開銷較大。

  • 類的實例化的頻率較高。

效果:

  • 節(jié)省了創(chuàng)建類實例的開銷。

  • 節(jié)省了創(chuàng)建類實例的時間。

  • 存儲空間隨著對象的增多而增大。

問題

目前縱觀主流語言的實現(xiàn)方式無外乎3個步驟:

  1. 初始創(chuàng)建一定數(shù)量的對象池(也允許從外面添加對象)。

  2. 從對象池中取對象來使用。

  3. 用完之后返回對象池。

一般情況下這樣是OK的,可能存在的問題是在第三步,有兩個問題:

  1. 不方便,每次都需要顯式回收對象。

  2. 忘記將對象放回對象池,造成資源浪費(fèi)。

改進(jìn)動機(jī)

解決顯式回收的問題,實現(xiàn)自動回收,省心省力。改進(jìn)之后的對象池?zé)o須提供release方法,對象會自動回收,改進(jìn)之后的類圖如下。

怎么深度剖析C++對象池自動回收技術(shù)實現(xiàn)

技術(shù)內(nèi)幕

借助c++11智能指針,因為智能指針可以自定義刪除器,在智能指針釋放的時候會調(diào)用刪除器,在刪除器中我們將用完的對象重新放回對象池。思路比較簡單,但實現(xiàn)的時候需要考慮兩個問題:

  1. 什么時候定義刪除器?

  2. 用shared_ptr還是unique_ptr?

1. 什么時候定義刪除器

自定義刪除器只做一件事,就是將對象重新放入對象池。如果對象池初始化的時候就自定義刪除器的話,刪除器中的邏輯是將對象放回對象池,放回的時候無 法再定義一個這樣的刪除器,所以這種做法行不通。需要注意,回收的對象只能是默認(rèn)刪除器的。除了前述原因之外,另外一個原因是對象池釋放的時候需要釋放所 有的智能指針,釋放的時候如果存在自定義刪除器將會導(dǎo)致對象無法刪除。只有在get的時候定義刪除器才行,但是初始創(chuàng)建或加入的智能指針是默認(rèn)刪除器,所 以我們需要把智能指針的默認(rèn)刪除器改為自定義刪除器。

1.2 用shared_ptr還是unique_ptr

因為我們需要把智能指針的默認(rèn)刪除器改為自定義刪除器,用shared_ptr會很不方便,因為你無法直接將shared_ptr的刪除器修改為自 定義刪除器,雖然你可以通過重新創(chuàng)建一個新對象,把原對象拷貝過來的做法來實現(xiàn),但是這樣做效率比較低。而unique_ptr由于是獨占語義,提供了一 種簡便的方法方法可以實現(xiàn)修改刪除器,所以用unique_ptr是最適合的。

1.3 實現(xiàn)源碼

#pragma once #include <memory> #include <vector> #include <functional>  template <class T> class SimpleObjectPool { public:     using DeleterType = std::function<void(T*)>;      void add(std::unique_ptr<T> t)     {         pool_.push_back(std::move(t));     }      std::unique_ptr<T, DeleterType> get()     {         if (pool_.empty())         {             throw std::logic_error("no more object");         }          //every time add custom deleter for default unique_ptr         std::unique_ptr<T, DeleterType> ptr(pool_.back().release(), [this](T* t)         {             pool_.push_back(std::unique_ptr<T>(t));         });          pool_.pop_back();         return std::move(ptr);     }      bool empty() const     {         return pool_.empty();     }      size_t size() const     {         return pool_.size();     }  private:     std::vector<std::unique_ptr<T>> pool_; };  //test code void test_object_pool() {     SimpleObjectPool<A> p;     p.add(std::unique_ptr<A>(new A()));     p.add(std::unique_ptr<A>(new A()));     {         auto t = p.get();         p.get();     }      {         p.get();         p.get();     }      std::cout << p.size() << std::endl; }

如果你堅持用shared_ptr,那么回收的時候你需要這樣寫:

std::shared_ptr<T> get() { if (pool_.empty()) {   throw std::logic_error("no more object"); }  std::shared_ptr<T> ptr = pool_.back(); auto p = std::shared_ptr<T>(new T(std::move(*ptr.get())), [this](T* t) {   pool_.push_back(std::shared_ptr<T>(t)); });  //std::unique_ptr<T, DeleterType> ptr(pool_.back().release(), [this](T* t) //{ // pool_.push_back(std::unique_ptr<T>(t)); //});  pool_.pop_back(); return p; }

這種方式需要每次都創(chuàng)建一個新對象,并且拷貝原來的對象,是一種比較低效的做法。代碼僅僅是為了展示如何實現(xiàn)自動回收對象,沒有考慮線程安全、對象池擴(kuò)容策略等細(xì)節(jié),源碼鏈接:object_pool

總結(jié)凡是需要自動回收的場景下都可以使用這種方式:在獲取對象的時候?qū)⒛J(rèn)刪除器改為自定義刪除器,確保它可以回收。注意,回收的智能指針使用的是 默認(rèn)刪除器,可以確保對象池釋放時能正常釋放對象。同時也將獲取對象和釋放對象時,對象的控制權(quán)完全分離。其他的一些應(yīng)用場景:多例模式,無需手動釋放, 自動回收。

上述內(nèi)容就是怎么深度剖析C++對象池自動回收技術(shù)實現(xiàn),你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

c++
AI