Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/149.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ std::函数作为回调函数,是否可以取消注册?_C++_C++11 - Fatal编程技术网

C++ std::函数作为回调函数,是否可以取消注册?

C++ std::函数作为回调函数,是否可以取消注册?,c++,c++11,C++,C++11,问题严格地说是关于std::function,而不是boost::function。有关更多详细信息,请参阅此问题底部的更新部分,特别是关于无法按照C++11标准比较非空std::function对象的部分 C++11std::function类模板非常适合维护回调集合。例如,可以将它们存储在向量中,并在需要时调用它们。然而,维护这些对象并允许注销似乎是不可能的 让我具体地说,想象一下这个类: class Invoker { public: void Register(std::funct

问题严格地说是关于
std::function
,而不是
boost::function
。有关更多详细信息,请参阅此问题底部的更新部分,特别是关于无法按照C++11标准比较非空
std::function
对象的部分


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

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

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()
};
类调用程序
{
公众:
无效寄存器(std::函数f);
作废注销(std::函数f);
void InvokeAll();
私人:
//保存传递给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);
}
void foo()
{
}
int main()
{
std::函数f1{foo};

std::function f2{[]{std::cout由于无法测试容器中的元素标识,因此最好使用容器(如
std::list
),其迭代器在修改容器时不会失效,并将迭代器返回给注册调用方,以用于注销

如果确实要使用
向量
(或
deque
),您可以在添加回调时将整数索引返回到vector/deque中。此策略自然要求您确保索引以这种方式可用,以标识函数在序列中的位置。如果回调和/或注销很少,这可能意味着不重用spot。或者,您可以实现free list以重用空插槽。或者,仅从序列的末尾回收空插槽,并保持基本索引偏移量,该偏移量在从开始回收插槽时增加


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

我有一个想法

将回调存储为
std::weak_ptr
。然后调用者负责保持相应的
std::shared_ptr
处于活动状态,调用者取消注册回调所需做的一切就是将所有活动的
std::shared_ptr
销毁到回调函数

调用回调时,代码必须仔细检查它正在使用的
std::weak_ptr
s上的锁失败。当它运行在这些锁上时,可以将它们从注册回调的容器中删除


请注意,这并不能提供完整的线程安全性,因为回调调用程序可以锁定
std::weak_ptr
,并临时激活回调函数的
std::shared_ptr
,在调用程序的
std::shared_ptr
超出范围后,该函数可以保持活动状态。

您可以像MS那样处理连接点:返回cookie(索引到向量中)调用方提供撤销注册。我通常将接口指针存储为回调并将它们放入集合中。然后,我可以按值访问注销。@罗杰罗兰德好主意。@ WooZravig Boost也为他们的一个类做了。在做了C++程序员17年之后,我终于知道了使用<代码> STD::列表< /COD>本身的理由。