我有一个回调系统,可以在发生事件时保存lambda。要获得通知,您必须将lambda注册到标识符,或者如果您不想再次通知则取消注册。
我遇到的问题是我已经注册了lambdas,在被调用时将从该系统取消注册,导致正在执行的当前lambda的破坏。而且我认为这不安全。但我不确定。
简化例如:
#include <map>
#include <functional>
#include <iostream>
int main() {
std::map<int, std::function<void ()>> m;
m[10] = [&m] () {
int i = m.size(); // Just cheking the internal state of the lambda
m.clear();
//i += m.size(); // If I uncomment this the std::cout is not working.
std::cout<< "What happens? " << i << std::endl;
};
m[10]();
return 0;
}
我所看到的是,当我在m.clear()
之后检查lambda的状态时,我会遇到奇怪的行为(例如std::cout
无效)。你能解释一下这些情况下究竟发生了什么吗?
你将如何处理回调的情况?在调用回调之前制作副本(似乎是禁止的)?
答案 0 :(得分:5)
考虑发生了什么:您在<{1}}内存储了使用 lambda表达式生成的函数对象。
std::function<void()>
现在拥有生成的功能对象。它也位于std::function
内。
然后,您可以通过引用捕获相同的std::map
并在其上调用std::map::clear
,删除存储的std::map
。
来自std::function
上的std::map::clear
文档:
从容器中删除所有元素。 使引用包含元素的任何引用,指针或迭代器无效。任何过去的迭代器仍然有效。
可以安全地假设cppreference.org
clear
使存储在其中的数据无效。因此,使用存储在生成的函数对象中的数据是不安全的,可能会导致未定义的行为。
这是粗略简化你正在做的事情:
std::map