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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/497922.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RK3566和Robo_C的EMC防护设计细节

USB部分的防护细节&#xff1a; ROBO C的USB接口&#xff1a; PF级别的电容滤波&#xff1a; TVS电容&#xff08;TVS Capacitor&#xff09;&#xff1a;用于与TVS二极管配合&#xff0c;保护电路免受瞬态电压冲击。电容一般较小&#xff0c;通常为几十皮法&#xff08;pF&am…

如果你的网站是h5网站,如何将h5网站变成小程序-除开完整重做方法如何快速h5转小程序-h5网站转小程序的办法-优雅草央千澈

如果你的网站是h5网站&#xff0c;如何将h5网站变成小程序-除开完整重做方法如何快速h5转小程序-h5网站转小程序的办法-优雅草央千澈 h5如何转小程序 如果当年你们开发网站是用的h5但是没有开发小程序&#xff0c;也没有使用uniapp这样的混开框架&#xff0c;但是目前根据业务需…

30天面试打卡计划 2024-12-25 26 27 面试题

2024-12-25 面试题 后端 MySQL三层B树能存多少数据&#xff1f; B 树&#xff1a;一种特殊的多路平衡查找树&#xff0c;广泛应用于数据库索引中。它具有所有叶子节点都位于同一层且包含指向相邻叶子节点指针的特点&#xff0c;这使得范围查询更加高效。InnoDB&#xff1a;My…

微信流量主挑战:用户破16!新增文档转换(新纪元3)

朋友们&#xff0c;报告好消息&#xff01;我的小程序用户数量已经涨到16个了&#xff01;没错&#xff0c;真没拉朋友圈亲戚好友来撑场子&#xff0c;全靠实力&#xff08;和一点点运气&#xff09;吸引了16位陌生小伙伴光临&#xff01;这波进步&#xff0c;连我自己都感动了…

阿里云redis内存优化——PCP数据清理

在阿里云安装了一个redis节点&#xff0c;今天使用时忽然想着点击了一下分析内存。好家伙&#xff0c;居然崩出了一个30多M的块出来。问题是我本地安装的redis没有这个啊&#xff0c;怎么奇怪冒出这个来了。 本着把系统用干榨尽的态度&#xff0c;研究了下这个问题的来源。网上…

常见的排序算法过程和比较分析

比较分析 排序类别排序算法时间复杂度&#xff08;最好&#xff09;时间复杂度&#xff08;最坏&#xff09;时间复杂度&#xff08;平均&#xff09;辅助空间复杂度稳定性插入排序直接插入排序O(n)O(n)O(n)O(1)稳定插入排序折半插入排序O(n)O(n)O(n)O(1)稳定插入排序希尔排序…

webrtc-internals调试工具

Google 的 Chrome&#xff08;87 或更高版本&#xff09;WebRTC 内部工具是一套内置于 Chrome 浏览器中的调试工具; webrtc-internals 能够查看有关视频和音频轨道、使用的编解码器以及流的一般质量的详细信息。这些知识对于解决音频和视频质量差的问题非常有帮助。 webrtc-int…

VS Code中怎样查看某分支的提交历史记录

VsCode中无法直接查看某分支的提交记录&#xff0c;需借助插件才行&#xff0c;常见的插件如果git history只能查看某页面的改动记录&#xff0c;无法查看某分支的整体提交记录&#xff0c;我们可以安装GIT Graph插件来解决这个问题 1.在 VSCode的插件库中搜索 GIT Graph安装&a…

超详细!一文搞定PID!嵌入式STM32-PID位置环和速度环

本文目录 一、知识点1. PID是什么&#xff1f;2. 积分限幅--用于限制无限累加的积分项3. 输出值限幅--用于任何pid的输出4. PID工程 二、各类PID1. 位置式PID&#xff08;用于位置环&#xff09;&#xff08;1&#xff09;公式&#xff08;2&#xff09;代码使用代码 2. 增量式…

学习solid works第八课------工程图

一、新建工程图 工程图创建不像零件和装配体一样直接点击新建&#xff0c;工程图跟零件的关联在一起的&#xff0c;我们需要需要先打开零件&#xff0c;在零件中建立对应的工程图。 1. 打开需要做工程图的零件&#xff08;以一颗螺丝为例子&#xff09;。 2. 在文件下拉菜单中…

Python 爬虫

一、创建项目 1.双击打开pycharm&#xff0c;点击新建项目 2.项目设置- 勾选[继承全局站点软件包]- 勾选[可用于所有项目]- 取消勾选[创建main.py欢迎脚本]- 点击创建 3.项目名称右键--新建--python文件 4.输入文件名--回车二、编辑代码 # 导入请求模块 import requests # 如…

Azure Function 解决跨域问题

这边前端call本地部署的azure function出现了跨域问题&#xff0c;搜索一下解决方案 直接修改local.setting.json&#xff0c;在其中添加CORS配置为通配符”*”&#xff0c;就行了 local.settings.json {"IsEncrypted": false,"Values": {"PYTHON_E…

【Unity】手把手入门2D游戏开发教程——小狐狸的冒险(上)

‍ 前言&#xff1a;本文章教程&#xff0c;结合Unity官方教程和网上其他资源教程进行整合&#xff0c;目的是让大家可以更快速地上手&#xff0c;减少大家观看比较理论的教程或者视频时长偏长的教程的时间。‍‍‍‍‍ 本文章参考了以下有关文献或内容&#xff1a; SIKI视频教…

Chapter 03 复合数据类型-1

1.列表 Python内置的一种有序、可变的序列数据类型&#xff1b; 列表的定义&#xff1a; [ ]括起来的逗号分隔的多个元素组成的序列 列表对象的创建&#xff1a; &#xff08;1&#xff09;直接赋值 >>> list1 []#创建一个空列表赋值给list1 >>> list…

【Webug】攻防实战详情

世界上只有一种真正的英雄主义&#xff0c;那就是认清了生活的真相后&#xff0c;仍然热爱她 显错注入 首先整体浏览网站 注入点&#xff1a; control/sqlinject/manifest_error.php?id1 判断注入类型 输入: and 11 正常, 再输入: and 12 还正常, 排除数字型 输入单引号:…

Linux day1204

五.安装lrzsz lrzsz 是用于在 Linux 系统中文件上传下载的软件。大家可能会存在疑问&#xff0c;我们用 MobaXterm 图形化界面就可以很方便的完成上传下载&#xff0c;为什么还要使用这个软件来 完成上传下载呢&#xff1f;实际上是这样的&#xff0c; Linux 的远程连接工具…

linux-21 目录管理(一)mkdir命令,创建空目录

对linux而言&#xff0c;对一个系统管理来讲&#xff0c;最关键的还是文件管理。那所以我们接下来就来看看如何实现文件管理。当然&#xff0c;在文件管理之前&#xff0c;我们说过&#xff0c;文件通常都放在目录下&#xff0c;对吧&#xff1f;所以先了解目录&#xff0c;可能…

Docker基础知识 Docker命令、镜像、容器、数据卷、自定义镜像、使用Docker部署Java应用、部署前端代码、DockerCompose一键部署

目录 1.Docker 2.镜像和容器 2.1 定义 2.2 开机自动启动容器 3.docker命令 3.1 docker run 参数说明 3.2 常见命令 3.3 命令演示 3.4 命令别名 4.Docker命令详解 5.数据卷 5.1 定义 5.2 数据卷的相关命令 5.3 数据卷命令 5.4 挂载本地目录或文件 5.4.1 定义 5.4.2 mysql容器目录…

SOME/IP 协议详解——信息格式

文章目录 1. 头部格式1.1 消息 ID&#xff08;Message ID&#xff09;1.2 长度&#xff08;Length&#xff09;1.3 请求 ID&#xff08;Request ID&#xff09;1.4 协议版本&#xff08;Protocol Version&#xff09;&#xff1a;1.5 接口版本&#xff08;Interface Version&am…

HarmonyOS NEXT 实战之元服务:静态案例效果---电动车电池健康状况

背景&#xff1a; 前几篇学习了元服务&#xff0c;后面几期就让我们开发简单的元服务吧&#xff0c;里面丰富的内容大家自己加&#xff0c;本期案例 仅供参考 先上本期效果图 &#xff0c;里面图片自行替换 效果图1完整代码案例如下&#xff1a; import { authentication } …