webrtc源码浅析-scoped_ref_ptr

webrtc实现的一个智能指针,代码很简单。在析构的时候调用release方法,增加引用的时候使用add方法。

先上代码:

/*
 *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

// Originally these classes are from Chromium.
// http://src.chromium.org/viewvc/chrome/trunk/src/base/memory/ref_counted.h?view=markup

//
// A smart pointer class for reference counted objects.  Use this class instead
// of calling AddRef and Release manually on a reference counted object to
// avoid common memory leaks caused by forgetting to Release an object
// reference.  Sample usage:
//
//   class MyFoo : public RefCounted<MyFoo> {
//    ...
//   };
//
//   void some_function() {
//     scoped_refptr<MyFoo> foo = new MyFoo();
//     foo->Method(param);
//     // |foo| is released when this function returns
//   }
//
//   void some_other_function() {
//     scoped_refptr<MyFoo> foo = new MyFoo();
//     ...
//     foo = NULL;  // explicitly releases |foo|
//     ...
//     if (foo)
//       foo->Method(param);
//   }
//
// The above examples show how scoped_refptr<T> acts like a pointer to T.
// Given two scoped_refptr<T> classes, it is also possible to exchange
// references between the two objects, like so:
//
//   {
//     scoped_refptr<MyFoo> a = new MyFoo();
//     scoped_refptr<MyFoo> b;
//
//     b.swap(a);
//     // now, |b| references the MyFoo object, and |a| references NULL.
//   }
//
// To make both |a| and |b| in the above example reference the same MyFoo
// object, simply use the assignment operator:
//
//   {
//     scoped_refptr<MyFoo> a = new MyFoo();
//     scoped_refptr<MyFoo> b;
//
//     b = a;
//     // now, |a| and |b| each own a reference to the same MyFoo object.
//   }
//

#ifndef WEBRTC_BASE_SCOPED_REF_PTR_H_
#define WEBRTC_BASE_SCOPED_REF_PTR_H_

#include <memory>

namespace rtc {

template <class T>
class scoped_refptr {
 public:
  scoped_refptr() : ptr_(NULL) {
  }

  scoped_refptr(T* p) : ptr_(p) {
    if (ptr_)
      ptr_->AddRef();
  }

  scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
    if (ptr_)
      ptr_->AddRef();
  }

  template <typename U>
  scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
    if (ptr_)
      ptr_->AddRef();
  }

  // Move constructors.
  scoped_refptr(scoped_refptr<T>&& r) : ptr_(r.release()) {}

  template <typename U>
  scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.release()) {}

  ~scoped_refptr() {
    if (ptr_)
      ptr_->Release();
  }

  T* get() const { return ptr_; }
  operator T*() const { return ptr_; }
  T* operator->() const { return ptr_; }

  // Release a pointer.
  // The return value is the current pointer held by this object.
  // If this object holds a NULL pointer, the return value is NULL.
  // After this operation, this object will hold a NULL pointer,
  // and will not own the object any more.
  T* release() {
    T* retVal = ptr_;
    ptr_ = NULL;
    return retVal;
  }

  scoped_refptr<T>& operator=(T* p) {
    // AddRef first so that self assignment should work
    if (p)
      p->AddRef();
    if (ptr_ )
      ptr_ ->Release();
    ptr_ = p;
    return *this;
  }

  scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
    return *this = r.ptr_;
  }

  template <typename U>
  scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
    return *this = r.get();
  }

  scoped_refptr<T>& operator=(scoped_refptr<T>&& r) {
    scoped_refptr<T>(std::move(r)).swap(*this);
    return *this;
  }

  template <typename U>
  scoped_refptr<T>& operator=(scoped_refptr<U>&& r) {
    scoped_refptr<T>(std::move(r)).swap(*this);
    return *this;
  }

  void swap(T** pp) {
    T* p = ptr_;
    ptr_ = *pp;
    *pp = p;
  }

  void swap(scoped_refptr<T>& r) {
    swap(&r.ptr_);
  }

 protected:
  T* ptr_;
};

}  // namespace rtc

#endif  // WEBRTC_BASE_SCOPED_REF_PTR_H_

这里的demo说的很清楚。单纯这个智能指针式是不能用的。需要一个定义了Add和Release方法的类。

可以直接实现这个接口:

// Reference count interface.
class RefCountInterface {
 public:
  virtual int AddRef() const = 0;
  virtual int Release() const = 0;

 protected:
  virtual ~RefCountInterface() {}
};


或者使用webrtc提供的这样一个类:

/*
 *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#ifndef WEBRTC_BASE_REFCOUNT_H_
#define WEBRTC_BASE_REFCOUNT_H_

#include <string.h>
#include <utility>

#include "webrtc/base/atomicops.h"

namespace rtc {

// Reference count interface.
class RefCountInterface {
 public:
  virtual int AddRef() const = 0;
  virtual int Release() const = 0;

 protected:
  virtual ~RefCountInterface() {}
};

template <class T>
class RefCountedObject : public T {
 public:
  RefCountedObject() {}

  template <typename P>
  explicit RefCountedObject(const P& p) : T(p) {}

  template <typename P>
  explicit RefCountedObject(P&& p) : T(std::move(p)) {}

  template <typename P1, typename P2>
  RefCountedObject(P1 p1, P2 p2) : T(p1, p2) {}

  template <typename P1, typename P2, typename P3>
  RefCountedObject(P1 p1, P2 p2, P3 p3) : T(p1, p2, p3) {}

  template <typename P1, typename P2, typename P3, typename P4>
  RefCountedObject(P1 p1, P2 p2, P3 p3, P4 p4) : T(p1, p2, p3, p4) {}

  template <typename P1, typename P2, typename P3, typename P4, typename P5>
  RefCountedObject(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) : T(p1, p2, p3, p4, p5) {}

  template <typename P1,
            typename P2,
            typename P3,
            typename P4,
            typename P5,
            typename P6>
  RefCountedObject(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)
      : T(p1, p2, p3, p4, p5, p6) {}

  template <typename P1,
            typename P2,
            typename P3,
            typename P4,
            typename P5,
            typename P6,
            typename P7>
  RefCountedObject(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7)
      : T(p1, p2, p3, p4, p5, p6, p7) {}

  template <typename P1,
            typename P2,
            typename P3,
            typename P4,
            typename P5,
            typename P6,
            typename P7,
            typename P8>
  RefCountedObject(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8)
      : T(p1, p2, p3, p4, p5, p6, p7, p8) {}

  template <typename P1,
            typename P2,
            typename P3,
            typename P4,
            typename P5,
            typename P6,
            typename P7,
            typename P8,
            typename P9>
  RefCountedObject(P1 p1,
                   P2 p2,
                   P3 p3,
                   P4 p4,
                   P5 p5,
                   P6 p6,
                   P7 p7,
                   P8 p8,
                   P9 p9)
      : T(p1, p2, p3, p4, p5, p6, p7, p8, p9) {}

  template <typename P1,
            typename P2,
            typename P3,
            typename P4,
            typename P5,
            typename P6,
            typename P7,
            typename P8,
            typename P9,
            typename P10>
  RefCountedObject(P1 p1,
                   P2 p2,
                   P3 p3,
                   P4 p4,
                   P5 p5,
                   P6 p6,
                   P7 p7,
                   P8 p8,
                   P9 p9,
                   P10 p10)
      : T(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) {}

  template <typename P1,
            typename P2,
            typename P3,
            typename P4,
            typename P5,
            typename P6,
            typename P7,
            typename P8,
            typename P9,
            typename P10,
            typename P11>
  RefCountedObject(P1 p1,
                   P2 p2,
                   P3 p3,
                   P4 p4,
                   P5 p5,
                   P6 p6,
                   P7 p7,
                   P8 p8,
                   P9 p9,
                   P10 p10,
                   P11 p11)
      : T(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) {}

  virtual int AddRef() const { return AtomicOps::Increment(&ref_count_); }

  virtual int Release() const {
    int count = AtomicOps::Decrement(&ref_count_);
    if (!count) {
      delete this;
    }
    return count;
  }

  // Return whether the reference count is one. If the reference count is used
  // in the conventional way, a reference count of 1 implies that the current
  // thread owns the reference and no other thread shares it. This call
  // performs the test for a reference count of one, and performs the memory
  // barrier needed for the owning thread to act on the object, knowing that it
  // has exclusive access to the object.
  virtual bool HasOneRef() const {
    return AtomicOps::AcquireLoad(&ref_count_) == 1;
  }

 protected:
  virtual ~RefCountedObject() {}

  mutable volatile int ref_count_ = 0;
};

}  // namespace rtc

#endif  // WEBRTC_BASE_REFCOUNT_H_


我们的关注点在release()和add()函数的实现上,追进去代码看:


/*
 *  Copyright 2011 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#ifndef WEBRTC_BASE_ATOMICOPS_H_
#define WEBRTC_BASE_ATOMICOPS_H_

#if defined(WEBRTC_WIN)
// Include winsock2.h before including <windows.h> to maintain consistency with
// win32.h.  We can't include win32.h directly here since it pulls in
// headers such as basictypes.h which causes problems in Chromium where webrtc
// exists as two separate projects, webrtc and libjingle.
#include <winsock2.h>
#include <windows.h>
#endif  // defined(WEBRTC_WIN)

namespace rtc {
class AtomicOps {
 public:
#if defined(WEBRTC_WIN)
  // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64.
  static int Increment(volatile int* i) {
    return ::InterlockedIncrement(reinterpret_cast<volatile LONG*>(i));
  }
  static int Decrement(volatile int* i) {
    return ::InterlockedDecrement(reinterpret_cast<volatile LONG*>(i));
  }
  static int AcquireLoad(volatile const int* i) {
    return *i;
  }
  static void ReleaseStore(volatile int* i, int value) {
    *i = value;
  }
  static int CompareAndSwap(volatile int* i, int old_value, int new_value) {
    return ::InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(i),
                                        new_value,
                                        old_value);
  }
  // Pointer variants.
  template <typename T>
  static T* AcquireLoadPtr(T* volatile* ptr) {
    return *ptr;
  }
  template <typename T>
  static T* CompareAndSwapPtr(T* volatile* ptr, T* old_value, T* new_value) {
    return static_cast<T*>(::InterlockedCompareExchangePointer(
        reinterpret_cast<PVOID volatile*>(ptr), new_value, old_value));
  }
#else
  static int Increment(volatile int* i) {
    return __sync_add_and_fetch(i, 1);
  }
  static int Decrement(volatile int* i) {
    return __sync_sub_and_fetch(i, 1);
  }
  static int AcquireLoad(volatile const int* i) {
    return __atomic_load_n(i, __ATOMIC_ACQUIRE);
  }
  static void ReleaseStore(volatile int* i, int value) {
    __atomic_store_n(i, value, __ATOMIC_RELEASE);
  }
  static int CompareAndSwap(volatile int* i, int old_value, int new_value) {
    return __sync_val_compare_and_swap(i, old_value, new_value);
  }
  // Pointer variants.
  template <typename T>
  static T* AcquireLoadPtr(T* volatile* ptr) {
    return __atomic_load_n(ptr, __ATOMIC_ACQUIRE);
  }
  template <typename T>
  static T* CompareAndSwapPtr(T* volatile* ptr, T* old_value, T* new_value) {
    return __sync_val_compare_and_swap(ptr, old_value, new_value);
  }
#endif
};



}

#endif  // WEBRTC_BASE_ATOMICOPS_H_

发现仅仅是个多线程安全的引用计数。这里考虑了跨平台的实现,linux如上。windows还要在追一下:


#ifndef __WINDOWS2LINUX_H__
#define __WINDOWS2LINUX_H__

/*
 * LINUX SPECIFIC DEFINITIONS
*/
//
// Data types conversions
//
#include <stdlib.h>
#include <string.h>
#include "basicDataTypeConversions.h"

#ifdef __cplusplus
namespace avxsynth {
#endif // __cplusplus
//
// purposefully define the following MSFT definitions
// to mean nothing (as they do not mean anything on Linux)
//
#define __stdcall
#define __cdecl
#define noreturn
#define __declspec(x)
#define STDAPI       extern "C" HRESULT
#define STDMETHODIMP HRESULT __stdcall
#define STDMETHODIMP_(x) x __stdcall

#define STDMETHOD(x)    virtual HRESULT x
#define STDMETHOD_(a, x) virtual a x

#ifndef TRUE
#define TRUE  true
#endif

#ifndef FALSE
#define FALSE false
#endif

#define S_OK                (0x00000000)
#define S_FALSE             (0x00000001)
#define E_NOINTERFACE       (0X80004002)
#define E_POINTER           (0x80004003)
#define E_FAIL              (0x80004005)
#define E_OUTOFMEMORY       (0x8007000E)

#define INVALID_HANDLE_VALUE    ((HANDLE)((LONG_PTR)-1))
#define FAILED(hr)              ((hr) & 0x80000000)
#define SUCCEEDED(hr)           (!FAILED(hr))


//
// Functions
//
#define MAKEDWORD(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
#define MAKEWORD(a,b) (((a) << 8) | (b))

#define lstrlen                             strlen
#define lstrcpy                             strcpy
#define lstrcmpi                            strcasecmp
#define _stricmp                            strcasecmp
#define InterlockedIncrement(x)             __sync_fetch_and_add((x), 1)
#define InterlockedDecrement(x)             __sync_fetch_and_sub((x), 1)
// Windows uses (new, old) ordering but GCC has (old, new)
#define InterlockedCompareExchange(x,y,z)   __sync_val_compare_and_swap(x,z,y)

#define UInt32x32To64(a, b)                 ( (uint64_t) ( ((uint64_t)((uint32_t)(a))) * ((uint32_t)(b))  ) )
#define Int64ShrlMod32(a, b)                ( (uint64_t) ( (uint64_t)(a) >> (b) ) )
#define Int32x32To64(a, b)                  ((__int64)(((__int64)((long)(a))) * ((long)(b))))

#define MulDiv(nNumber, nNumerator, nDenominator)   (int32_t) (((int64_t) (nNumber) * (int64_t) (nNumerator) + (int64_t) ((nDenominator)/2)) / (int64_t) (nDenominator))

#ifdef __cplusplus
}; // namespace avxsynth
#endif // __cplusplus

#endif //  __WINDOWS2LINUX_H__


会发现和unix上的是一样的实现,做了小封装。


总结:


scoped_ref_ptr 是个简单的智能(根据引用数量延迟销毁,不会多次重复new,节省开销)指针,多线程安全(使用_sync_fetch_and_add比加锁要高效的多)。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值