我试图编写一个简单但灵活的事件系统(大多数情况下只是作为练习,我知道现有的库有非常好的事件处理程序),而且我遇到了一个小绊脚石。
如果成员函数的对象在调用之前仍然存在,那么如何检查std::function
委托(可能通过lambda,可能是std :: bind)是否为有效函数?我尝试过使用std::function's
bool运算符,但没有取得任何成功。
理想情况下,我希望A.在委托函数内部以外的位置进行检查,并且当正在检查的std :: function不是&时,代码仍然有效。 ta delegate。
有什么想法吗?
编辑:这是我跑的测试的来源
#include <iostream>
#include <string>
#include <functional>
class Obj {
public:
std::string foo;
Obj(std::string foo) : foo(foo) {}
std::function<void()> getDelegate() {
auto callback = [this]() {this->delegatedFn();};
return callback;
}
void delegatedFn() {
std::cout << foo << std::endl;
}
};
int main() {
Obj* obj = new Obj("bar");
std::function<void()> callback = obj->getDelegate();
callback();
delete obj;
//perform some type of check here whether function is valid, without needing to know whether the function is a delegate or not
if(callback) {
std::cout << "Callback is valid" << std::endl; //callback is still considered valid after obj is deleted
callback(); //no exception thrown, prints a random series of characters
}
else {
std::cout << "Callback is invalid" << std::endl;
}
return 0;
}
答案 0 :(得分:4)
您可以使用智能指针(std::shared_ptr
/ std::weak_ptr
)而不是裸指针:
#include <iostream>
#include <string>
#include <functional>
#include <memory>
class Obj {
public:
std::string foo;
Obj(std::string foo) : foo(foo) {}
void delegatedFn() {
std::cout << foo << std::endl;
}
};
int main() {
auto obj = std::make_shared<Obj>("bar");
std::weak_ptr<Obj> ptr = obj;
std::function<void()> callback = [ptr](){
auto sh = ptr.lock();
if(sh) { std::cout << "valid" << std::endl; sh->delegatedFn(); }
else { std::cout << "invalid" << std::endl; }
};
callback();
obj = nullptr;
callback();
return 0;
}
在这种情况下,您不是直接检查std::function
的有效性(当您为其指定某些内容时有效,即使某些内容捕获了悬空指针)
相反,您可以在函数本身内检查引用的对象是否仍然存在。
答案 1 :(得分:2)
我使用的广播/监听模式如下所示:
template<class...Args>
struct broadcaster {
std::vector< std::weak_ptr< std::function<void(Args...)> > > callbacks;
void operator()(Args...args) const {
std::remove_erase_if( begin(callbacks), end(callbacks), [](auto&& ptr){return !ptr;} );
auto tmp = callbacks;
for (auto pf : tmp) {
if (pf && *pf) (*pf)(args...);
}
}
std::shared_ptr<void> listen( std::shared_ptr<std::function<void(Args...)>> f ) {
callbacks.push_back(f);
return f;
}
std::shared_ptr<void> listen( std::function<void(Args...)> f ) {
auto ptr = std::make_shared<std::function<void(Args...)>>(std::move(f));
return listen(ptr);
}
};
使用.listen
收听回复邮件broadcaster
。他们返回shared_ptr<void>
令牌。
只要存在该令牌,广播公司就会在传入的功能对象上发送消息。
Obj
会存储std::vector<std::shared_ptr<void>> tokens
或单std::shared_ptr<void>
。当它被销毁时,它的听众会自动注销。
或者,Obj
可以从shared_from_this
继承。然后它实现
std::function<void()> delegate;
std::shared_ptr<std::function<void()>> getDelegatedFn() {
if (!delegate) delegate = [this]{ this->delegateFn(); }
return {
&delegate,
shared_from_this()
};
}
,它共享Obj
实例本身的生命周期(使用shared_ptr
的别名构造函数)。将此传递给listen
并完成。