欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 焦点 > webrtc 源码阅读 make_ref_counted模板函数用法

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

2025/1/4 11:36:53 来源:https://blog.csdn.net/Wu_qz/article/details/144634202  浏览:    关键词:webrtc 源码阅读 make_ref_counted模板函数用法

目录

1. 模板参数解析

1.1 typename T

1.2 typename... Args

1.3 typename std::enable_if::value, T>::type* = nullptr

2. scoped_refptr

3. new RefCountedObject(std::forward(args)...);

4. 综合说明

5.在webrtc中的用法

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类等都是采用这种方式初始化对象的

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com