webrtc 源码阅读 make_ref_counted模板函数用法

目录

[1. 模板参数解析](#1. 模板参数解析)

[1.1 typename T](#1.1 typename T)

[1.2 typename... Args](#1.2 typename... Args)

[1.3 typename std::enable_if::value, T>::type* = nullptr](#1.3 typename std::enable_if::value, T>::type* = nullptr)

[2. scoped_refptr](#2. scoped_refptr)

[3. new RefCountedObject(std::forward(args)...);](#3. new RefCountedObject(std::forward(args)...);)

[4. 综合说明](#4. 综合说明)

5.在webrtc中的用法

[5.1 peerConnectionFactory对象的构建过程](#5.1 peerConnectionFactory对象的构建过程)


先看make_ref_counted模板函数的定义

template <
    typename T,
    typename... Args,
    typename std::enable_if<std::is_convertible<T*, RefCountInterface*>::value,
                            T>::type* = nullptr>
scoped_refptr<T> make_ref_counted(Args&&... args) {
  return new RefCountedObject<T>(std::forward<Args>(args)...);
}

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

  template <class P0>
  explicit RefCountedObject(P0&& p0) : T(std::forward<P0>(p0)) {}

  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)...) {}

  void AddRef() const override { ref_count_.IncRef(); }

  RefCountReleaseStatus Release() const override {
    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:
  ~RefCountedObject() override {}

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

  RTC_DISALLOW_COPY_AND_ASSIGN(RefCountedObject);
};

WebRTC 源码中的一个 make_ref_counted 函数模板,它用于创建具有引用计数的对象。通过使用 C++ 的 SFINAE (Substitution Failure Is Not An Error)和 std::enable_if ,该函数确保只有在某些条件下才能创建对象,这些条件是 T 类型必须能够转换为 RefCountInterface*

对如上源码解读:

1. 模板参数解

1.1 typename T
  • T 是模板的类型参数,表示要创建的对象类型。例如,如果你想创建一个 MyClass 类型的对象,则 T 将是 MyClass
1.2 typename... Args
  • Args 是一个 可变模板参数 ,表示你可以传入任意数量的构造函数参数。这使得 make_ref_counted 可以用于创建任何带有不同构造参数的对象。
1.3 typename std::enable_if<std::is_convertible<T*, RefCountInterface*>::value, T>::type* = nullptr
  • 这一部分使用了 SFINAE 技巧来约束模板的实例化条件。通过 std::enable_ifstd::is_convertible,它确保只有当 T*(即 T 类型的指针)能够转换为 RefCountInterface* 类型时,才会启用该模板。

    • std::is_convertible<T*, RefCountInterface*>::value 是一个类型特性(type trait),它检查类型 T* 是否可以转换为 RefCountInterface*。如果可以转换,表达式的值为 true,否则为 false
    • 如果 T* 可以转换为 RefCountInterface*,则 std::enable_if 会定义类型别名 type,从而允许模板实例化。
    • 如果 T* 不能转换为 RefCountInterface*,则模板实例化将失败,不会生成该函数。
  • std::enable_if<Condition, T>::type* :当条件成立时,enable_if 会提供一个类型别名 type,而 type* 是指向 T 类型的指针。= nullptr 是默认参数,表示 type* 参数是一个指针类型且值为 nullptr

2. scoped_refptr<T>

  • scoped_refptr<T> 是 WebRTC 中的智能指针,用于管理引用计数对象的生命周期。它会在对象超出作用域时自动减少引用计数,如果引用计数降到零,T 类型的对象会被销毁。

    在这段代码中,scoped_refptr<T> 被用作返回类型,表示 make_ref_counted 函数会返回一个智能指针,管理创建的对象。

3. new RefCountedObject<T>(std::forward<Args>(args)...);

  • new RefCountedObject<T>(std::forward<Args>(args)...); 会创建一个新的 RefCountedObject<T> 对象,并传递参数 args 给其构造函数。RefCountedObject<T> 是一个继承自 RefCountInterface 的类,用于为对象提供引用计数功能。

    • std::forward<Args>(args)...:这个语法用于完美转发参数。如果 Args 是一个左值引用类型,那么它会以左值方式传递;如果是右值,则会以右值方式传递。完美转发保证了参数的传递不发生不必要的拷贝或移动。

    • RefCountedObject<T> 是 WebRTC 中专门为引用计数管理而设计的一个模板类,它负责管理 T 类型的对象的生命周期。当 scoped_refptr<T> 被销毁时,它会自动减少 RefCountedObject<T> 的引用计数。

4. 综合说明

整个函数的作用是创建一个 T 类型的对象,并将其包装在一个具有引用计数的智能指针(scoped_refptr<T>)中。它的关键是通过 std::enable_if 限制,只有当 T 类型能够转换为 RefCountInterface* 时,才会进行实例化,确保只有支持引用计数的对象才会被创建。

5.在webrtc中的用法

5.1 peerConnectionFactory对象的构建过程

从webrtc源码看peerConnectionFactory类的继承关系如下图所示。它公有继承自PeerConnectionFactoryInterface(抽象类),而PeerConnectionFactoryInterface又公有继承自RefCountInterface(抽象类)。peerConnectionFactory并没有实现父抽象类的虚函数,所以 peerConnectionFactory也是一个抽象类,那是如何创建出peerConnectionFactory对象呢?

如下代码是webrtc创建peerConnectionFactory对象的位置,

rtc::scoped_refptr<PeerConnectionFactory> PeerConnectionFactory::Create(
    PeerConnectionFactoryDependencies dependencies) {
  auto context = ConnectionContext::Create(&dependencies);
  if (!context) {
    return nullptr;
  }
  return rtc::make_ref_counted<PeerConnectionFactory>(context, &dependencies);
}

根据上述对make_ref_counted的介绍,因为PeerConnectionFactory类型可以转换成RefCountInterface*类型,

new RefCountedObject<T>(std::forward<Args>(args)...);

所以如上这行代码,是把peerConnectionFactory类型当做模版类型T传入。展开后的代码应该长这样:

new RefCountedObject<peerConnectionFactory>(context, &dependencies);

对于模板类RefCountedObject,内部实现了RefCountInterface抽象类的两个接口。

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

  template <class P0>
  explicit RefCountedObject(P0&& p0) : T(std::forward<P0>(p0)) {}

  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)...) {}

  void AddRef() const override { ref_count_.IncRef(); }

  RefCountReleaseStatus Release() const override {
    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:
  ~RefCountedObject() override {}

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

  RTC_DISALLOW_COPY_AND_ASSIGN(RefCountedObject);
};

所以调用

rtc::scoped_refptr<PeerConnectionFactory> PeerConnectionFactory::Create(

PeerConnectionFactoryDependencies dependencies) {

auto context = ConnectionContext::Create(&dependencies);

if (!context) {

return nullptr;

}

return rtc::make_ref_counted<PeerConnectionFactory>(context, &dependencies);

}

后,接着调用rtc::make_ref_counted模版函数后,在这个模版函数内是new一个模版类,这个模版类的参数类型是PeerConnectionFactory。

new RefCountedObject<T>(std::forward<Args>(args)...);

最终看到的PeerConnectionFactory对象,其实是在其外部又封装了一层。这样做的好处是PeerConnectionFactory对象会在其生命期结束后释放对象,实现这个功能主要是靠rtc::scoped_refptr实现的。有时间再接着介绍rtc::scoped_refptr。

从下图可以看出创建的peerConnectionFactory对象确实是来自模板类RefCountedObject。

类似PeerConnection类、EncoderStreamFactory类、 VideoRtpSender类等都是采用这种方式初始化对象的

相关推荐
宇寒风暖1 小时前
侯捷 C++ 课程学习笔记:内存管理与工具应用
c++·笔记·学习
云缘若仙1 小时前
directx12 3d+vs2022游戏开发第六章 笔记十一
笔记·directx12 3d
电棍2332 小时前
在wsl环境中配置和开发verilog(一种比较新颖的verilog开发指南)
笔记
非 白3 小时前
【Java】单例模式
java·笔记·单例模式
明阳mark3 小时前
Ansible 学习笔记
笔记·学习·ansible
StickToForever5 小时前
第4章 信息系统架构(六)
经验分享·笔记·学习·职场和发展
东方芷兰9 小时前
伯克利 CS61A 课堂笔记 11 —— Mutability
笔记·python
快下雨了L14 小时前
C++面试笔记(持续更新...)
笔记
柃歌15 小时前
【UCB CS 61B SP24】Lecture 7 - Lists 4: Arrays and Lists学习笔记
java·数据结构·笔记·学习·算法
JANGHIGH15 小时前
c++ std::list使用笔记
c++·笔记·list