Chromium的智能指針/引用計數/Callback/Bind

這四個東西對使用者來講不難,看懂代碼註釋裏的例子便可,預計1小時左右看懂所有。要去理解其設計思想的話最須要掌握的是模板類的使用,但通常使用者徹底不用關心怎麼設計的。chrome

使用者的學習路徑:數組

1.智能刪除指針scoped_ptr

用做對普通指針的轉儲,防止忘記delete或不知道哪裏delete。它跟引用計數沒有關係。安全

頭文件的註釋就是使用示例閉包

http://src.chromium.org/viewvc/chrome/trunk/src/base/memory/scoped_ptr.h函數

template <class T, class D = base::DefaultDeleter<T> > class scoped_ptr學習

其中Deleter能夠被替換,默認的Deleter區分是要delete普通指針仍是指針數組,或者用free函數刪除malloc的內存。ui

2.ScopedVector

http://src.chromium.org/viewvc/chrome/trunk/src/base/memory/scoped_vector.hthis

在析構時會delete其元素的vector,知道它的行爲便可。spa

3.帶引用計數的類

http://src.chromium.org/viewvc/chrome/trunk/src/base/memory/ref_counted.h線程

爲了不模板類的代碼膨脹,引入基類base::subtle::RefCountedBase。基類很簡單,就是最基本的引用計數,帶AddRef和Release函數。

模 板類template <class T> class RefCounted : public subtle::RefCountedBase相對地就只在Release函數內作特殊處理:delete static_cast<const T*>(this)

另外RefCountedThreadSafeBase和模板類RefCountedThreadSafe是線程安全的版本。

4.引用計數的智能指針scoped_refptr

同在ref_counted.h裏定義,對RefCounted的子類作引用。scoped_refptr就是構造時調用RefCounted子類的AddRef函數和析構時Release,並提供了操做符的重載。

5.WeakPtr

弱引用指針,用做傳遞指針但不想更換owner的狀況,即明確知道誰去釋放但其它引用者不肯定其時機,用弱引用指針可隨時知道其是否已delete。

http://src.chromium.org/viewvc/chrome/trunk/src/base/memory/weak_ptr.h

看文件裏的註釋便可。

6.Callback

對函數的閉包封裝,頭文件的註釋就是使用示例

http://src.chromium.org/viewvc/chrome/trunk/src/base/callback.h

要注意註釋裏提到的對傳入參數的要求。Callback最多提供帶7個參數的函數封裝,其協做類很是多但都不須要去理解。

(理解設計的提示:很是多的模板類,用做抽象各類各樣的函數簽名;有不少的輔助類和typedef,最好本身整理成圖來看清它們的關係)

7.Bind

對Callback的便捷封裝,Bind就是返回Callback對象。

http://src.chromium.org/viewvc/chrome/trunk/src/base/bind.h

看看頭文件知道它是個模板函數併爲不一樣參數個數作了重載就好了。

(理解設計的提示:查看http://src.chromium.org/viewvc/chrome/trunk/src/base/bind_internal.h文件的註釋)



對scoped_ptr的理解:

沒有引用計數的類,使用scoped_ptr<class T, class D>。這個模板類中的D是指Deleter,表明如何刪除T。引入Deleter最簡單的緣由就是對數組須要使用delete[]操做符,實際上有4個默認的Deleter。


3個Deleter都是經過重載括號運算符來執行實際的delete操做,而常量長度的數組指針是不容許使用智能指針的,這裏也聲明出來,能在編譯階段就排除錯誤。

除了DefaultDeleter,還有一些特殊的Deleter,如disk cache使用的EntryDeleter(disk_cache.h),字節對齊的內存使用的 AlignedFreeDeleter(aligned_memory.h),他們都有本身的括號運算符重載實現,由於這是scoped_ptr模板類要 求的的方式。

scoped_ptr還有個基類template <class T, class D> class scoped_ptr_impl,它實現了scoped_ptr的核心功能,這樣抽離出來是由於有些地方不須要更多的功能。這是模板類,多一個函數就可能 多好多個實現。

scoped_ptr_impl定義了內部類Data來繼承Deleter,實際就是增長了ptr來保存傳入的裸指針(raw pointer / bare pointer)。

struct Data : public D {
    explicit Data(T* ptr_in) : ptr(ptr_in) {}
    Data(T* ptr_in, const D& other) : D(other), ptr(ptr_in) {}
    T* ptr;
};

Data data_;

scoped_ptr_impl的主要函數:

  explicit scoped_ptr_impl(T* p) : data_(p) { }

  ~scoped_ptr_impl() {
    if (data_.ptr != NULL) {
      // Not using get_deleter() saves one function call in non-optimized
      // builds.
      static_cast<D&>(data_)(data_.ptr);
    }
  }
  void reset(T* p) {
    // This is a self-reset, which is no longer allowed: http://crbug.com/162971
    if (p != NULL && p == data_.ptr)
      abort();
    T* old = data_.ptr;
    data_.ptr = NULL;
    if (old != NULL)
      static_cast<D&>(data_)(old);
    data_.ptr = p;
  }
  T* get() const { return data_.ptr; }
  D& get_deleter() { return data_; }
  const D& get_deleter() const { return data_; }
  void swap(scoped_ptr_impl& p2) {
    using std::swap;
    swap(static_cast<D&>(data_), static_cast<D&>(p2.data_));
    swap(data_.ptr, p2.data_.ptr);
  }
  T* release() {
    T* old_ptr = data_.ptr;
    data_.ptr = NULL;
    return old_ptr;
  }

scoped_ptr是獨立的模板類

template <class T, class D = base::DefaultDeleter<T> > class scoped_ptr

template <class T, class D> base::scoped_ptr<T[], D>

它有惟一的成員變量

base::internal::scoped_ptr_impl<element_type, deleter_type> impl_
便是組合scoped_ptr_impl,而不是用繼承(也就是橋接模式)。impl有的函數,scoped_ptr都有,並多了重載運算符,以便使用者能直接使用智能指針作其它操做:

typedef T element_type


內存釋放的流程:scoped_ptr析構=>impl_析構=>調用deleter=>delete element_type


對引用計數的理解:

有引用計數的智能指針則簡單多了:


其中T是自己實現了引用計數的類。


爲了不模板類,引入基類:


基類都是這老一套,用變量保存引用數,沒啥說的。

模板類:

template <class T>
class RefCounted : public subtle::RefCountedBase {
 public:
  RefCounted() {}

  void AddRef() const {
    subtle::RefCountedBase::AddRef();
  }

  void Release() const {
    if (subtle::RefCountedBase::Release()) {
      delete static_cast<const T*>(this);
    }
  }

 protected:
  ~RefCounted() {}

 private:
  DISALLOW_COPY_AND_ASSIGN(RefCounted<T>);
};


參考:

相關文章
相關標籤/搜索