使用智能指针和lambda函数 - 删除对象

时间:2015-05-28 17:25:33

标签: c++ lambda smart-pointers delete-operator

我想实现一个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!

0 个答案:

没有答案