背景
好多开发者可能会疑惑,你一个搞音视频开发的,怎么做起了C++基础普及的事情?搞音视频底层开发的,大多需要有相对好的C C++基础,这里提到的std::remove_if,也是因为大牛直播SDK的demo代码里面有用到。有些对接的开发者容易疑惑,做个基础的扫盲。
以我们Linux平台RTSP|RTMP多路播放的demo为例,我们针对event handler做了封装,大概的设计如下:
/*
* nt_sdk_handle_wrapper.h
* Created by daniusdk.com (C) All rights reserved.
*/
class NT_SDK_HandleWrapper
{
public:
explicit NT_SDK_HandleWrapper(SmartPlayerSDKAPI* sdk_api);
~NT_SDK_HandleWrapper();
public:
void AddEventHandler(const std::shared_ptr<NT_SDK_EventHandler>& handler);
void RemoveHandler(const std::shared_ptr<NT_SDK_EventHandler>& handler);
void RemoveHandler(const NT_SDK_EventHandler* handler);
...
private:
std::recursive_mutex event_handlers_mutex_;
std::vector<std::weak_ptr<NT_SDK_EventHandler> > event_handlers_;
};
其他不再赘述,针对AddEventHandler()和RemoveHandler()处理如下:
void NT_SDK_HandleWrapper::AddEventHandler(const std::shared_ptr<NT_SDK_EventHandler>& handler)
{
assert(handler);
std::unique_lock<std::recursive_mutex> lock(event_handlers_mutex_);
auto iter = std::find_if(begin(event_handlers_), end(event_handlers_),
[&handler](const std::weak_ptr<NT_SDK_EventHandler>& i)->bool
{
if (i.lock() == handler)
{
return true;
}
return false;
});
if (iter == end(event_handlers_))
{
event_handlers_.push_back(handler);
}
}
void NT_SDK_HandleWrapper::RemoveHandler(const std::shared_ptr<NT_SDK_EventHandler>& handler)
{
assert(handler);
std::unique_lock<std::recursive_mutex> lock(event_handlers_mutex_);
auto iter = std::remove_if(begin(event_handlers_), end(event_handlers_),
[&handler](const std::weak_ptr<NT_SDK_EventHandler>& i)->bool
{
if (i.lock() == handler)
{
return true;
}
return false;
}
);
if (iter != end(event_handlers_))
{
event_handlers_.erase(iter, end(event_handlers_));
}
}
void NT_SDK_HandleWrapper::RemoveHandler(const NT_SDK_EventHandler* handler)
{
assert(handler != nullptr);
std::unique_lock<std::recursive_mutex> lock(event_handlers_mutex_);
auto iter = std::remove_if(begin(event_handlers_), end(event_handlers_),
[&handler](const std::weak_ptr<NT_SDK_EventHandler>& i)->bool
{
auto obj = i.lock();
if (!obj)
{
return true;
}
if (obj.get() == handler)
{
return true;
}
return false;
}
);
if (iter != end(event_handlers_))
{
event_handlers_.erase(iter, end(event_handlers_));
}
}
std::remove_if扫盲
这里部分开发者可能会有疑惑,std::remove_if
是 C++ 标准库中的一个算法函数,定义在 <algorithm>
头文件中。它的主要功能是根据用户提供的条件,将容器中满足该条件的元素移除。
std::remove_if
的函数签名如下:
template< class ForwardIt, class UnaryPredicate >
ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPredicate p );
参数解释:
first
和last
:表示容器中元素范围的迭代器,[first, last)
是要操作的元素范围。p
:一个一元谓词函数,接受一个参数,其返回值是bool
类型。该谓词函数会对[first, last)
范围内的元素进行判断,返回true
表示该元素应该被移除。
工作原理:
std::remove_if
并不会真正从容器中删除元素,因为它没有办法改变容器的大小。实际上,它会将不需要移除的元素移动到容器的前面,并返回一个新的 “逻辑结束” 迭代器,该迭代器指向最后一个不需要移除元素的下一个位置。- 为了真正删除元素,你需要结合容器的
erase
成员函数,使用erase-remove_if
惯用法。
总结
std::remove_if
适用于顺序容器,如vector
、list
、deque
等。- 对于关联容器(如
set
、map
),由于它们有自己的删除元素的成员函数,并且元素存储是有序的,不应该使用std::remove_if
。 - 在使用
erase-remove_if
惯用法时,要确保容器支持erase
操作。
通过这种方式,你可以方便地根据自定义条件从容器中移除元素,并且代码简洁高效。