删除绑定到成员函数的 vector<std::function<...>> 的任何元素
remove any element of vector<std::function<...>> that bound to member function
如何删除绑定到this
对象成员函数的函数:
std::vector<std::function<void(int)>> callbacks;
class MyClass {
public:
MyClass() {
callbacks.push_back(
std::bind(&MyClass::myFunc,this,std::placeholders::_1)
);
}
~MyClass() {
auto it = std::remove_if( std::begin(callbacks),
std::end(callbacks),
[&](std::function<void(int)>& f) {
return // <-- this is my question
// true (remove) if f is bound to member function
// of this
});
callbacks.erase(it,std::end(callbacks));
}
void myFunc(int param){...}
};
typedef decltype(std::bind(&MyClass::myFunc,this,std::placeholders::_1)) bound_type;
auto it = std::remove_if( std::begin(callbacks),
std::end(callbacks),
[](const std::function<void(int)>& f) {
return f.target<bound_type>() != nullptr;
});
成员函数模板std::function::target<T>
返回指向目标对象的指针(如果它是 T
类型),否则返回 null。因此,您只需要能够命名目标对象的类型,可以从中获取 decltype
.真的很简单:-)
注意,这将删除该类型的任何回调,而不仅仅是那些绑定了要销毁的特定对象的this
指针的回调。如果你试图阻止在对象被销毁后调用对象的回调,并且无法识别向量的哪些元素引用哪些对象,你可以考虑在你的类中放置一个shared_ptr,然后在回调中存储一个weak_ptr,这可以用来检测对象是否已被销毁:
class MyClass
{
struct NullDeleter { void operator()(void*) const { } };
std::shared_ptr<MyClass> sp;
static void safe_invoke(void (MyClass::*f)(int), const std::weak_ptr<MyClass>& wp, int i)
{
if (std::shared_ptr<MyClass> safe_this = wp.lock())
(safe_this.get()->*f)(i);
}
public:
MyClass() : sp(this, NullDeleter()) {
callbacks.push_back(
std::bind(safe_invoke, &MyClass::myFunc ,std::weak_ptr<MyClass>(sp),
std::placeholders::_1)
);
};
这会将对成员函数的调用包装为在调用成员函数之前将weak_ptr
转换为shared_ptr
的 invoke
函数。如果对象已被销毁,则shared_ptr
将为空,因此该函数不执行任何操作。 这实际上不会在回调变为无效时将其删除,但确实可以安全地调用。
在一般情况下,如果没有大量的额外工作,你就无法做到。类型擦除会从对象中清除此信息,并且std::function
不会直接公开此信息。
您的特定示例可能只有一个成员函数可以作为要删除的候选项,但是具有 5 个成员的类可以存储为回调呢?您需要测试所有这些函数,并且还可以使用 lambda 绑定成员函数,这几乎无法检测到。
在以下情况下,以下解决方案如下:
- 所有回调都是从
MyClass
中注册
的 - 修改容器以存储额外信息
- 你愿意做所有额外的簿记
std::vector<std::pair<std::function<void(int)>, void*>> callbacks;
class MyClass{
static unsigned const num_possible_callbacks = 2; // keep updated
std::array<std::type_info const*, num_possible_callbacks> _infos;
unsigned _next_info;
// adds type_info and passes through
template<class T>
T const& add_info(T const& bound){
if(_next_info == num_possible_callbacks)
throw "oh shi...!"; // something went out of sync
_infos[_next_info++] = &typeid(T);
return bound;
}
public:
MyClass() : _next_info(0){
using std::placeholders::_1;
callbacks.push_back(std::make_pair(
add_info(std::bind(&MyClass::myFunc, this, _1)),
(void*)this));
callbacks.push_back(std::make_pair(
add_info([this](int i){ return myOtherFunc(i, 0.5); }),
(void*)this));
}
~MyClass(){
using std::placeholders::_1;
callbacks.erase(std::remove_if(callbacks.begin(), callbacks.end(),
[&](std::pair<std::function<void(int)>, void*> const& p) -> bool{
if(p.second != (void*)this)
return false;
auto const& f = p.first;
for(unsigned i = 0; i < _infos.size(); ++i)
if(_infos[i] == &f.target_type())
return true;
return false;
}), callbacks.end());
}
void myFunc(int param){ /* ... */ }
void myOtherFunc(int param1, double param2){ /* ... */ }
};
Ideone上的活生生的例子。
我曾经需要做这样的事情,我通过在包含该函数的类中存储对象的共享指针的向量来解决它,并在它们被销毁时按值从向量中删除函数,这也使这成为自动的。
相关文章:
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 呼叫运营商<<临时
- 如何防止clang格式在流运算符调用之间添加换行符<<
- <<操作员在下面的行中工作
- EASTL矢量<向量<int>>连续的
- C - 创建矢量&lt; vector&lt; double&gt;&gt;矩阵具有分配而不是inizializ
- 为什么将此对向量&lt; map&lt; int,int&gt;&gt;中的地图进行更新.失败
- C :对矢量进行排序&lt; struct&gt;(结构有2个整数)基于结构的整数之一
- 明确的专业化“ CheckIntmap&lt;&gt;”实例化
- 什么是模板&lt;&gt;inline bla bla
- 编辑C Qlist&lt; object*&gt; gt;QML代码和一些QML警告中的模型
- eigen :: llt&lt;eigen :: matrixxd&gt;具有不完整的类型
- 错误,包括&lt; ctype&gt;在原子上使用C 11
- std::vector<;uint8_t>;当C++11/14启用时,手动复制而不是调用memcpy
- 如何加入向量&lt; int&gt;到C 中的单个INT
- 是std :: set&lt; std :: future&gt;不可能存在
- 是numeric_limits&lt; int&gt; :: is_modulo从逻辑上矛盾
- opencv 2.4.7在iOS错误背景_segm.hpp #include&lt; list&gt;未找到
- 在修改列表后,std :: list&lt; t&gt; :: end()的值是否会更改
- ///<评论></评论>在Visual Studio中