将存储在其中的任何元素存储一段时间的容器

时间:2014-05-27 08:27:20

标签: c++ boost

我需要一个容器,用于存储推入其中的任何元素10分钟。我该怎么做?为此目的,我应该使用类似boost::deadline_timer的东西吗?

我尝试编写以下代码:

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time.hpp>
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/thread.hpp>

#include <map>
#include <utility>

namespace koicxx {

template <typename T>
class temp_storage : private boost::noncopyable
{
  typedef boost::shared_ptr<boost::asio::deadline_timer>                    shared_timer_t;
  typedef std::map<T, shared_timer_t>                                       timer_map_t;
  typedef std::pair<T, shared_timer_t>                                      timer_pair_t;
  typedef boost::function<void(const T&, const boost::system::error_code&)> callback_t;

public:
  temp_storage(boost::asio::io_service& io_service) :
    _io_service(io_service) {}

  bool add(const T& element, const boost::asio::deadline_timer::duration_type& timeout, callback_t callback = callback_t())
  {
    boost::lock_guard<boost::mutex> lock(_sync);

    const std::pair<timer_map_t::iterator, bool>& res =
      _internal_storage.insert(
        timer_pair_t(
          element
          , shared_timer_t(new boost::asio::deadline_timer(_io_service, timeout))
        ));

    if (!res.second)
    {
        return false;
    }

    const timer_map_t::iterator& itr = res.first;

    if (callback)
    {
      itr->second->async_wait(
        boost::bind(
          callback
          , itr->first
          , boost::asio::placeholders::error
        ));
    }

    itr->second->async_wait(
      boost::bind(
        &temp_storage::remove_callback
        , this
        , itr->first
        , boost::asio::placeholders::error
      ));

    return true;
  }

  bool remove(const T& element)
  {
    boost::lock_guard<boost::mutex> lock(_sync);

    const timer_map_t::iterator& itr = _internal_storage.find(element);
    if (itr == _internal_storage.end())
    {
        return false;
    }
    itr->second->cancel();

    _internal_storage.erase(itr);

    return true;
  }

  bool contains(const T& element)
  {
    boost::lock_guard<boost::mutex> lock(_sync);

    return _internal_storage.find(element) != _internal_storage.end();
  }

  void clear()
  {
    boost::lock_guard<boost::mutex> lock(_sync);

    for (timer_map_t::value_type& i : _internal_storage)
    {
        i.second->cancel();
    }

    _internal_storage.clear();
  }

private:
  void remove_callback(const T& element, const boost::system::error_code& e)
  {
    if (e == boost::asio::error::operation_aborted)
    {
        return;
    }
    remove(element);
  }

  boost::asio::io_service&  _io_service;
  timer_map_t               _internal_storage;
  boost::mutex              _sync;
};

} // namespace koicxx

int main()
{
  boost::asio::io_service io_service;
  io_service.run();
  koicxx::temp_storage<int> some_storage(io_service);
  some_storage.add(0, boost::posix_time::seconds(2));
  some_storage.add(1, boost::posix_time::seconds(3));
  some_storage.add(2, boost::posix_time::seconds(5));

  while (true)
  {
    if (some_storage.contains(0))
    {
      std::cout << 0 << ' ';
    }
    if (some_storage.contains(1))
    {
      std::cout << 1 << ' ';
    }
    if (some_storage.contains(2))
    {
      std::cout << 2 << ' ';
    }
    std::cout << '\n';

    boost::this_thread::sleep_for(boost::chrono::seconds(1));
  }
}

但它没有按预期工作 - 它始终给出“0 1 2”输出。为什么?我究竟做错了什么?我该如何解决?

1 个答案:

答案 0 :(得分:1)

也许这可以帮到你。

#include <vector>
#include <memory>
#include <chrono>
#include <algorithm>
#include <string>

using timepoint = std::chrono::time_point<std::chrono::system_clock>;

//type erasure code
struct Holder{
    virtual timepoint getCreationTime() const = 0;
    virtual ~Holder(){}
};

template <class T>
struct HolderHelper : Holder{
    HolderHelper(std::unique_ptr<T> &&up, timepoint t = timepoint::clock::now()) :
        object(std::move(up)), creationtime(t){}
    std::unique_ptr<T> object;
    timepoint creationtime;
    timepoint getCreationTime() const final override{
        return creationtime;
    }
};

//convenience wrapper
//it can be made more convenient if you limit yourself to movable objects
template <class T>
std::unique_ptr<Holder> make_timed_holder(std::unique_ptr<T> &&up){
    return std::unique_ptr<Holder>(new HolderHelper<T>(std::move(up)));
}

template <class T>
std::unique_ptr<Holder> make_timed_holder(std::unique_ptr<T> &&up, timepoint t){
    return std::unique_ptr<Holder>(new HolderHelper<T>(std::move(up), t));
}

//usage
int main(){
    //using a vector as a container, can be any other container
    std::vector<std::unique_ptr<Holder>> v;

    //inserting different objects
    v.push_back(make_timed_holder(std::make_unique<int>(42)));
    v.push_back(make_timed_holder(std::make_unique<std::string>("Hello")));
    v.push_back(make_timed_holder(std::make_unique<std::vector<std::vector<std::string>>>()));

    //removing all objects that have run out of time
    /*  for a sequence container the outdated objects are always in the front,
        so you can make the search faster
        For a set you can use the creation time as a key and make it search quicker that way
    */
    auto now = timepoint::clock::now();
    v.erase(std::remove_if(begin(v), end(v), [&](std::unique_ptr<Holder> &u){
        return u->getCreationTime() + std::chrono::minutes(10) < now;
    }), end(v));
}

您可能需要implement your own make_unique