目录
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::value,
T>::type* = nullptr>
scoped_refptr make_ref_counted(Args&&... args) {
return new RefCountedObject(std::forward(args)...);
}
template
class RefCountedObject : public T {
public:
RefCountedObject() {}
template
explicit RefCountedObject(P0&& p0) : T(std::forward(p0)) {}
template
RefCountedObject(P0&& p0, P1&& p1, Args&&... args)
: T(std::forward(p0),
std::forward(p1),
std::forward(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*
。
对如上源码解读:
typename T
T
是模板的类型参数,表示要创建的对象类型。例如,如果你想创建一个 MyClass
类型的对象,则 T
将是 MyClass
。typename... Args
Args
是一个 可变模板参数,表示你可以传入任意数量的构造函数参数。这使得 make_ref_counted
可以用于创建任何带有不同构造参数的对象。typename std::enable_if::value, T>::type* = nullptr
这一部分使用了 SFINAE 技巧来约束模板的实例化条件。通过 std::enable_if
和 std::is_convertible
,它确保只有当 T*
(即 T
类型的指针)能够转换为 RefCountInterface*
类型时,才会启用该模板。
std::is_convertible::value
是一个类型特性(type trait),它检查类型 T*
是否可以转换为 RefCountInterface*
。如果可以转换,表达式的值为 true
,否则为 false
。T*
可以转换为 RefCountInterface*
,则 std::enable_if
会定义类型别名 type
,从而允许模板实例化。T*
不能转换为 RefCountInterface*
,则模板实例化将失败,不会生成该函数。std::enable_if
:当条件成立时,enable_if
会提供一个类型别名 type
,而 type*
是指向 T
类型的指针。= nullptr
是默认参数,表示 type*
参数是一个指针类型且值为 nullptr
。
scoped_refptr
scoped_refptr
是 WebRTC 中的智能指针,用于管理引用计数对象的生命周期。它会在对象超出作用域时自动减少引用计数,如果引用计数降到零,T
类型的对象会被销毁。
在这段代码中,scoped_refptr
被用作返回类型,表示 make_ref_counted
函数会返回一个智能指针,管理创建的对象。
new RefCountedObject(std::forward(args)...);
new RefCountedObject
会创建一个新的 RefCountedObject
对象,并传递参数 args
给其构造函数。RefCountedObject
是一个继承自 RefCountInterface
的类,用于为对象提供引用计数功能。
std::forward
:这个语法用于完美转发参数。如果 Args
是一个左值引用类型,那么它会以左值方式传递;如果是右值,则会以右值方式传递。完美转发保证了参数的传递不发生不必要的拷贝或移动。
RefCountedObject
是 WebRTC 中专门为引用计数管理而设计的一个模板类,它负责管理 T
类型的对象的生命周期。当 scoped_refptr
被销毁时,它会自动减少 RefCountedObject
的引用计数。
整个函数的作用是创建一个 T
类型的对象,并将其包装在一个具有引用计数的智能指针(scoped_refptr
)中。它的关键是通过 std::enable_if
限制,只有当 T
类型能够转换为 RefCountInterface*
时,才会进行实例化,确保只有支持引用计数的对象才会被创建。
从webrtc源码看peerConnectionFactory类的继承关系如下图所示。它公有继承自PeerConnectionFactoryInterface(抽象类),而PeerConnectionFactoryInterface又公有继承自RefCountInterface(抽象类)。peerConnectionFactory并没有实现父抽象类的虚函数,所以peerConnectionFactory也是一个抽象类,那是如何创建出peerConnectionFactory对象呢?
如下代码是webrtc创建peerConnectionFactory对象的位置,
rtc::scoped_refptr PeerConnectionFactory::Create(
PeerConnectionFactoryDependencies dependencies) {
auto context = ConnectionContext::Create(&dependencies);
if (!context) {
return nullptr;
}
return rtc::make_ref_counted(context, &dependencies);
}
根据上述对make_ref_counted的介绍,因为PeerConnectionFactory类型可以转换成RefCountInterface*类型,
new RefCountedObject(std::forward(args)...);
所以如上这行代码,是把peerConnectionFactory类型当做模版类型T传入。展开后的代码应该长这样:
new RefCountedObject
对于模板类RefCountedObject,内部实现了RefCountInterface抽象类的两个接口。
template
class RefCountedObject : public T {
public:
RefCountedObject() {}
template
explicit RefCountedObject(P0&& p0) : T(std::forward(p0)) {}
template
RefCountedObject(P0&& p0, P1&& p1, Args&&... args)
: T(std::forward(p0),
std::forward(p1),
std::forward(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
PeerConnectionFactoryDependencies dependencies) {
auto context = ConnectionContext::Create(&dependencies);
if (!context) {
return nullptr;
}
return rtc::make_ref_counted
}
后,接着调用rtc::make_ref_counted模版函数后,在这个模版函数内是new一个模版类,这个模版类的参数类型是PeerConnectionFactory。
new RefCountedObject(std::forward(args)...);
最终看到的PeerConnectionFactory对象,其实是在其外部又封装了一层。这样做的好处是PeerConnectionFactory对象会在其生命期结束后释放对象,实现这个功能主要是靠rtc::scoped_refptr实现的。有时间再接着介绍rtc::scoped_refptr。
从下图可以看出创建的peerConnectionFactory对象确实是来自模板类RefCountedObject。
类似PeerConnection类、EncoderStreamFactory类、 VideoRtpSender类等都是采用这种方式初始化对象的