我有std::function
的列表。
当迭代列表时,将调用该函数,并且在某些情况下,它将在函数调用中被删除。在这种情况下,在for循环中递增迭代器时会发生崩溃,因为迭代器指向不存在的元素。
这是我的代码:
for (std::list<MessageCallback>::iterator it = _msg_callbacks.begin(); it != _msg_callbacks.end(); ++it) {
if (-1 == it->msg_type || msg_type == it->_msg_type) {
if (-1 == it->msg_id || response_msg_id == it->_msg_id) {
it->_msg_handler(msg_type, msg_id, data);
}
}
}
用户定义的msg_handler可能会调用remove_callback,其中回调将被其他迭代器擦除。
目前解决方法是在msg_handler调用周围添加++和it。
这是代码
for (std::list<MessageCallback>::iterator it = _msg_callbacks.begin(); it != _msg_callbacks.end(); ++it) {
if (-1 == it->msg_type || msg_type == it->_msg_type) {
if (-1 == it->msg_id || response_msg_id == it->_msg_id) {
std::function<...> handle = it->_msg_handler(msg_type, msg_id, data);
it++;
handle(msg_type, msg_id, data);
it--;
}
}
}
答案 0 :(得分:1)
您可以使用erase
并使用其返回值继续循环:
for (std::list<MessageCallback>::iterator it = _msg_callbacks.begin(); it != _msg_callbacks.end(); ++it) {
if (-1 == msg_type || msg_type == it->_msg_type) {
if (-1 == msg_id || response_msg_id == it->_msg_id) {
it->_msg_handler(msg_type, msg_id, data);
}
}
// some case to remove the function
it = _msg_callbacks.erase(it);
}
来自c std::list::erase上的cppreference.com:
返回值
跟随最后删除的元素的迭代器。如果迭代器pos引用最后一个元素,则返回end()迭代器。
修改强>
在你的问题的二读,看起来你的回调实际上删除了该功能。所以你能做的就是让它返回后擦除迭代器:
std::list<MessageCallback>::iterator foo_callback(
/* decltype */ msg_type,
/* decltype */ msg_id,
/* decltype */ data
)
{
// ...
// eventually extract iterator it from data; otherwise, you should pass it as argument
return _msg_callbacks.erase(it);
}
然后把它带回你的循环中:
for (std::list<MessageCallback>::iterator it = _msg_callbacks.begin(); it != _msg_callbacks.end(); ++it) {
if (-1 == msg_type || msg_type == it->_msg_type) {
if (-1 == msg_id || response_msg_id == it->_msg_id) {
it = it->_msg_handler(msg_type, msg_id, data);
}
}
}
答案 1 :(得分:1)
list::erase()
使所有迭代器,引用或指向擦除元素的指针无效,并将迭代器返回到最后擦除元素后面的元素。如果没有后续元素,则返回结束迭代器。
你的循环没有考虑到这一点。
因此,您需要找到一种方法来返回erase()
返回的迭代器,以便它可以在循环中使用。或者(假设你的回调只是擦除传递的迭代器)你的循环可以使用另一个iterator
(比如next_it
),在调用回调函数之前分配next_it = it + 1
,然后设置{{1而不是执行it = next_it
。