2016-11-23 79 views
-2

我有一個列表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調用中。

這裏是代碼

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

你的'msg_type'和'msg_id'在哪裏? –

+0

@appleapple MSG_TYPE和MSG_ID傳遞的功能參數 – gonglong

+0

(未回答),但比我想你不應該檢查'-1 == msg_type'內環路 –

回答

1

您可以使用erase,並使用它的返回值繼續你的循環:在std::list::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); 
} 

從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); 
     } 
    } 
} 
+0

感謝您的答覆,但很難使用戶在其定義的回調返回一個迭代,因爲所有回調的列表應該是透明的,他們 – gonglong

1

list::erase()會使所有的迭代器,引用或指針被擦除的元素(s),並將迭代器返回到最後擦除元素後面的元素。如果沒有後續元素,則返回結束迭代器。

您的循環沒有考慮到這一點。

因此,您需要找到一種方法來返回由erase()返回的迭代器,以便它可以在循環中使用。或者(假設你的回調只是刪除迭代器通過),你的循環可以使用另一個iterator(比如next_it),在調用回調函數之前分配next_it = it + 1,然後設置it = next_it而不是執行++it

+0

感謝您的解釋!你的第二個方法是比我更好的解決方法 – gonglong