c++ - std::function 作为回调,是否可以注销?

标签 c++ c++11

这个问题完全是关于 std::function而不是 boost::function .有关详细信息,请参阅此问题底部的 更新 部分,尤其是关于无法比较非空 std::function 的部分符合 C++11 标准的对象。


C++11 std::function类模板非常适合维护回调集合。可以将它们存储在 vector ,例如并在需要时调用它们。然而,维护这些对象并允许注销似乎是不可能的。

让我具体一点,想象一下这个类:

class Invoker
{
public:
  void Register(std::function<void()> f);
  void Unregister(std::function<void()> f);

  void InvokeAll();

private:
  // Some container that holds the function objects passed to Register()
};

示例使用场景:

void foo()
{
}

int main()
{
  std::function<void()> f1{foo};
  std::function<void()> f2{[] {std::cout << "Hello\n";} };

  Invoker inv;

  // The easy part

  // Register callbacks
  inv.Register(f1);
  inv.Register(f2);

  // Invoke them
  inv.InvokeAll();

  // The seemingly impossible part. How can Unregister() be implemented to actually
  // locate the correct object to unregister (i.e., remove from its container)?
  inv.Unregister(f2);
  inv.Unregister(f1);
}

很清楚Register()可以实现功能。但是,如何实现 Unregister() .假设保存函数对象的容器是 vector<std::function<void()>> .如何找到传递给 Unregister() 的特定函数对象?称呼? std::function确实提供了一个过载的 operator== ,但这仅测试空函数对象(即,它不能用于比较两个非空函数对象以查看它们是否都引用相同的实际调用)。

我会很感激任何想法。

更新:

目前的想法主要包括添加一个与每个 std::function 相关联的 cookie。可用于注销它的对象。我希望有一些与 std::function 无关的东西对象本身。此外,std::function 之间似乎存在很多混淆。和 boost::function .这个问题完全是关于 std::function对象,而不是 boost::function对象。

另外,你不能比较两个非空的 std::function平等的对象。根据标准,他们总是会比较不相等。因此,在此问题的上下文中,解决方案的评论中的链接(并使用 boost::function 启动对象)显然是错误的。

最佳答案

由于您无法测试容器中的元素标识,因此最好使用一个容器(例如 std::list),其迭代器不会在修改容器时失效,并且将迭代器返回给注册调用者,这些调用者可用于取消注册。

如果你真的想使用vector(或deque),你可以在添加回调时将整数索引返回到vector/deque。这种策略自然会要求您确保以这种方式使用索引来识别函数在序列中的位置。如果回调和/或注销很少见,这可能仅仅意味着不重复使用点。或者,您可以实现一个空闲列表来重用空槽。或者,仅从序列末尾回收空槽,并保持一个基本索引偏移量,当槽从开头回收时增加。

如果您的回调访问模式不需要随机访问遍历,则将回调存储在 std::list 中并使用原始迭代器取消注册对我来说似乎是最简单的。

关于c++ - std::function 作为回调,是否可以注销?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15916175/

相关文章:

c++ - 使用 engGetVariable 在 MATLAB R2014a 中检索结构时出错

c++ - 在 std::string 中使用自定义分配器重新使用已分配的 char 缓冲区

c++ - 我在链表实现中对 std::shared_ptr 和 std::unique_ptr 做错了什么?

c++ - std::hash 和/或 boost::hash 的目的是什么?

c++ - 复制到system32后文件会改变

c++ - 使用枚举基编写枚举时出现不明确的重载,但仅使用 clang

c++ - 查找数字的数字根

c++ - boost asio async_resolve 对象的生命周期

C++ 11 绑定(bind) std::function 与存储元组和解包

c++ - 使用抽象类的容器来容纳子类