webrtc中的引用计框架

webrtc中的引用计框架

基本框架类

webrtc中通过RefCounter,RefCountedObject,RefCountInterface类提供了一个引用计数框架。RefCounter是计数器类,实现了线程安全的计数功能;RefCountedObjectRefCounter进行了封装;RefCountInterface是接口类,要求实现AddRef()Release()接口。它们可以单独使用,可以结合使用。

在webrtc中有两个方面的运用

  • 使用scoped_refptr引用计数类时,需要把这上面的几个类结合起来使用

  • help_functions_ds.h文件中,实现了一个ComRefCount类,它是用来对COM组件进行管理的,它直接使用了RefCounter类,来实现引用计数

下面主要介绍scoped_refptr的实现及用法

scoped_refptr

实现

webrtc的代码中大量使用的scoped_refptr,是一个有引用计数的智能指针,与STL中的shared_ptr类似。不过它更轻量级,它的功能只限于增加/减少引用计数,超出作用域时自动释放所管理的对象。socped_refptr引用计数的实现为侵入式,它只有一个用于保存对象的指针变量,计数的功能由该对象实现可以通过RefCountedObject类来包装自定义类使其具有计数功能,来满足scoped_refptr的要求

代码比较简单,如下:

template <class T>
class scoped_refptr {
public:
 typedef T element_type;

 scoped_refptr() : ptr_(nullptr) {}

 scoped_refptr(T* p) : ptr_(p) {  // NOLINT(runtime/explicit)
   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) noexcept : ptr_(r.release()) {}

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

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

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

 // Returns the (possibly null) raw pointer, and makes the scoped_refptr hold a
 // null pointer, all without touching the reference count of the underlying
 // pointed-to object. The object is still reference counted, and the caller of
 // release() is now the proud owner of one reference, so it is responsible for
 // calling Release() once on the object when no longer using it.
 T* release() {
   T* retVal = ptr_;
   ptr_ = nullptr;
   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) noexcept {
   scoped_refptr<T>(std::move(r)).swap(*this);
   return *this;
 }

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

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

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

protected:
 T* ptr_;
};

scoped_refptr要求所管理的对象,实现了计数功能,它只保有指向该对象的一个裸指针。在复制构造函数,赋值函数中对计数进行增减。核心函数是scoped_refptr<T>& operator=(T* p),用T类型的裸指针给scoped_refptr赋值,对应的计数也会变化,这个跟STL中的智能指针不一样,不能将一个裸指针赋给智能指针。

有几个地方需要注意的

  • release()方法的语意是释放scoped_refptr对管理对象的所有权,对象超出作用域后,需要手动释放。这个跟STL中shared_ptr,unique_ptrrelease()方法的语意是一致的

  • scoped_refptr的构造

  1. 通过裸指针构造一个socped_refptr
scoped_refptr(T* p) : ptr_(p) {  // NOLINT(runtime/explicit)
   if (ptr_)
     ptr_->AddRef();
}
  1. 下面的这个复制构造函数,可以通过一个包装子类的scoped_refptr对象,构造一个包装父类的scoped_refptr对象
template <typename U>
 scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
   if (ptr_)
     ptr_->AddRef();
 }

例如:

//类s是类p的子类
scoped_refptr<s> sptr;

scoped_refptr<p> pPtr(sptr);

当然如果用一个没有继承关系的对象去构造,是会编译错误的。这是通过裸指针的多态实现。

用法

要使用scoped_refptr,通过了解RefCounter,RefCountedObject的功能,可以加深理解

  1. RefCounter

它就是实现了计数的类,它通过std::atomic<int>实现了线程安全的计数

  1. RefCountedObject

它封装了RefCounter,提供AddRef()Release()方法,满足scoped_refptr()的要求。但是对包装的类型要求是RefCountInterface

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

  //形参是右值引用,表示万能引用
  template <class P0>
  explicit RefCountedObject(P0&& p0) : T(std::forward<P0>(p0)) {}
  
  //形参是右值引用,表示万能引用,可以适配T类型的构造函数
  template <class P0, class P1, class... Args>
  RefCountedObject(P0&& p0, P1&& p1, Args&&... args)
      : T(std::forward<P0>(p0),
          std::forward<P1>(p1),
          std::forward<Args>(args)...) {}

  virtual void AddRef() const { ref_count_.IncRef(); }
  
  //Release包含了两个操作,将计数减1,如果再没有引用则释放对象
  virtual RefCountReleaseStatus Release() const {
    const auto status = ref_count_.DecRef();
    if (status == RefCountReleaseStatus::kDroppedLastRef) {
      delete this;
    }
    return status;
  }

  // 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 ref_count_.HasOneRef(); }

 protected:
  virtual ~RefCountedObject() {}

  mutable webrtc::webrtc_impl::RefCounter ref_count_{0};

  RTC_DISALLOW_COPY_AND_ASSIGN(RefCountedObject);
};
  1. RefCountInterface是个接口类
class RefCountInterface {
 public:
  virtual void AddRef() const = 0;
  virtual RefCountReleaseStatus Release() const = 0;

  // Non-public destructor, because Release() has exclusive responsibility for
  // destroying the object.
 protected:
  virtual ~RefCountInterface() {}
};
使用示例

对需要使用scoped_refptr管理的类,需要继承RefCountInterface, 然后在通过RefCountedObject包装。

#include <iostream>
#include "rtc_base/ref_counted_object.h"
#include "api/scoped_refptr.h"

//类Test继承RefCountInterface
class Test:public rtc::RefCountInterface {
  public:
    Test() = default;

    virtual void PrintTest() {
      std::cout<<"in Test PrintTest"<<std::endl;
    }
  protected:
    virtual ~Test() = default;
};

int main() {
    //通过RefCountedObject包装
    rtc::scoped_refptr<Test> ptr = new rtc::RefCountedObject<Test>();
    ptr->PrintTest();
}

猜你喜欢

转载自blog.csdn.net/mo4776/article/details/122417229