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