我想实现一个JavaScript style timeout function,它接受回调和时间延迟,并在指定的时间量结束后执行回调。之后应该销毁TimeOut
对象。
代码在上下文中执行,通过调用模块的onCycle()
方法提供循环代码执行。我想利用这个循环来检查时间是否已经过去,因为在这个循环之外没有代码执行是有意义的(这是由于硬件访问,这很慢)。在这个例子中(参见问题结尾),循环由ManagerClass
伪造,循环在无限循环中调用。
截至目前,我使用一个普通的指针,我通过lambda表达式的捕获列表来调用。我不喜欢这种方式,然后我删除了lambda执行中的指针:
void TimeOut::timeOut(const float &timeout, const std::function<void ()> &callback){
TimeOut* t = new TimeOut();
t->init(timeout, [t, callback]
{
callback();
t->connection_.disconnect();
delete t;
});
}
我的主要问题是,我更喜欢使用智能指针。但如果我做以下事情:
void TimeOut::timeOut(const float &timeout, const std::function<void ()> &callback){
std::shared_ptr<TimeOut> t = std::make_shared<TimeOut>();
t->init(timeout, [t, callback]
{
callback();
t->connection_.disconnect();
std::cout << t.use_count() << std::endl;
});
}
TimeOut
的析构函数不会被调用,shared_ptr
的引用计数器会计算剩余的一个引用。
有没有办法为这个特殊问题使用智能指针?或者我被迫保持现在的状态?
请参阅下面的(不是那样)最小工作示例。
#include <iostream>
#include <chrono>
#include <functional>
#include <cmath>
#include <boost/signals2.hpp>
class ManagerClass{
public:
static boost::signals2::signal<void()> cycleSignal;
};
boost::signals2::signal<void()> ManagerClass::cycleSignal;
class TimeOut
{
private:
/**
* @brief TimeOut Creates a new timeout that will trigger a callback after a specified amount of time.
* @param timeout the time in seconds from now, when the callback shall be executed.
* @param callback the callback to execute after 'timeout' seconds.
*/
void init(const float& timeout, const std::function<void ()>& callback);
std::function<void ()> callback_;
std::chrono::time_point<std::chrono::system_clock> pointOfExecution_;
boost::signals2::connection connection_;
public:
TimeOut();
~TimeOut();
static void timeOut(const float& timeout, const std::function<void ()>& callback);
void onCycle();
};
//IMPLEMENTATION of TimeOut:
TimeOut::TimeOut()
{
connection_ = ManagerClass::cycleSignal.connect(std::bind(&TimeOut::onCycle, this));
}
TimeOut::~TimeOut()
{
std::cout << "Destructor of TimeOut called!" << std::endl;
}
// getTimeDiff is a utility and is normally located elsewhere. Just for Completeness of the example.
inline float getTimeDiff(const std::chrono::time_point<std::chrono::system_clock>& lastTime){
std::chrono::duration<float> diff = std::chrono::system_clock::now() - lastTime;
return diff.count();
}
void TimeOut::onCycle()
{
if(getTimeDiff(pointOfExecution_) >= 0.0f ){
callback_();
}
}
void TimeOut::init(const float &timeout, const std::function<void ()> &callback)
{
callback_ = callback;
using namespace std::chrono;
pointOfExecution_ = time_point<system_clock>(system_clock::now() + milliseconds(static_cast<int>(round(timeout * 1000.0f))));
}
void TimeOut::timeOut(const float &timeout, const std::function<void ()> &callback){
TimeOut* t = new TimeOut();
t->init(timeout, [t, callback]
{
callback();
t->connection_.disconnect();
delete t;
});
}
// MAIN
int main()
{
//This is the exact syntax on how I want the interface to look like.
TimeOut::timeOut(2.0, []{
std::cout << "Hello World!" << std::endl;
});
//This infinite loop is a fake for the loop caused by
//a cycle that is specific to the hardware the code is
//running on. This just resembles a cyclic call of the onCycle method.
while(true){
ManagerClass::cycleSignal();
}
return 0;
}
输出
Hello World!
Destructor of TimeOut called!