在Active Object的实现中支持unique_ptr

时间:2015-04-15 00:13:36

标签: c++ multithreading c++11 c++14

我想创建一个Herb Sutter describes here的活动对象模式的现代(C ++ 11或C ++ 14)实现。此实现的一个特殊要求是,它支持通过std::unique_ptr安全所有权转移的消息,这些消息的复制成本过高。例如,应支持接近以下内容:

void sink(std::unique_ptr<int>) { /* ... */ }

Active active;
std::unique_ptr<int> unique(new int(0));
active.Send(std::bind(sink, unique));

以下与Herb's密切相关的实施方案不起作用。

#include <thread>
#include <queue>

// (Implementation of a threadsafe `message_queue` omitted.)

class Active {
public:
  typedef std::function<void()> Message;

  Active() : thd([&]{ Run(); }) {
  }

  ~Active() {
    Send([&]{ done = true; });
    thd.join();
  }

  void Send(Message m) {
    mq.send(m);
  }

private:
  bool done = false;
  message_queue<Message> mq;
  std::thread thd;

  void Run() {
    while (!done) {
      Message msg = mq.receive();
      msg();
    }
  }
};

通过此实现,上面的示例无法编译,错误表明无法从绑定类型转换为std::function<void()>。此错误源于std::function requires its argument to be CopyConstructiblebind unique_ptr生成不可复制的绑定对象这一事实。

是否有其他方法可以实现避免此问题的Active

1 个答案:

答案 0 :(得分:4)

这是一个类型擦除仅移动包装器的粗略草图,它能够保存任何可以在没有参数的情况下调用的可移动构造的函数对象。

struct Message {
    struct holder_base {
        virtual void operator()() = 0;
        virtual ~holder_base() = default;
    };

    template<class F>
    struct holder : holder_base {
        holder(F&& f) : func(std::move(f)) {}
        void operator()() override { func(); }
        F func;
    }; 

    Message() = default;
    Message(Message&&) = default;
    ~Message() = default;
    Message& operator=(Message&&) = default;

    // copy members implicitly deleted

    template<class F>
    Message(F func) : p_func(new holder<F>(std::move(func))) {}

    void operator()() const { (*p_func)(); }
    std::unique_ptr<holder_base> p_func;
};