{"id":411,"date":"2007-11-30T16:21:26","date_gmt":"2007-11-30T22:21:26","guid":{"rendered":"http:\/\/blog.codedread.com\/archives\/2007\/11\/30\/c-stl-safely-removing-items-from-a-container\/"},"modified":"2007-11-30T16:21:26","modified_gmt":"2007-11-30T22:21:26","slug":"c-stl-safely-removing-items-from-a-container","status":"publish","type":"post","link":"https:\/\/www.codedread.com\/blog\/archives\/2007\/11\/30\/c-stl-safely-removing-items-from-a-container\/","title":{"rendered":"C++ STL: Safely Removing Items From A Container"},"content":{"rendered":"<p>A short article about removing items from a standard C++ container.  <!--more--><\/p>\n<p>When using the C++ Standard Template Library, one has to be careful not to invalidate iterators in a container that you're iterating over.  If that makes any sense to you, then <!--more--><\/p>\n<div class=\"ads\"><object type=\"text\/html\" width=\"468\" height=\"60\" data=\"http:\/\/www.codedread.com\/gads.php\"><\/object><\/div>\n<p>A colleague of mine had code like this:<\/p>\n<p><code><\/p>\n<p>class TaskList {<\/p>\n<p>&#160;&#160;vector&#60;Task*> mTasks;<\/p>\n<p>&#160;&#160;typedef vector&#60;Task*>::iterator TaskIter;<\/p>\n<p>&#160;<\/p>\n<p>&#160;&#160;void removeTask(Task* t) {<\/p>\n<p>&#160;&#160;&#160;&#160;TaskIter it = find(mTasks.begin(),mTasks.end(),t);<\/p>\n<p>&#160;&#160;&#160;&#160;if(it != mTasks.end()) { mTasks.erase(it); }<\/p>\n<p>&#160;&#160;}<\/p>\n<p>&#160;<\/p>\n<p>&#160;public:<\/p>\n<p>&#160;&#160;void addTask(Task* t) { mTasks.push_back(t); }<\/p>\n<p>&#160;<\/p>\n<p>&#160;&#160;void processQueue() {<\/p>\n<p>&#160;&#160;&#160;&#160;for(TaskIter loopit=mTasks.begin();loopit!=mTasks.end();++loopit) {<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;Task* task = *loopit;<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;if(task->isNotDone()) {<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;task->doSomething();<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;}<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;else {<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;removeTask(task);<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;}<\/p>\n<p>&#160;&#160;&#160;&#160;}<\/p>\n<p>&#160;&#160;}<\/p>\n<p>};<\/p>\n<p><\/code><\/p>\n<p>You might be surprised to hear that the program crashed when the first task had to be removed.  The reason is that the removeTask() function erases an item out the collection which invalidates the iterator loopit.  When the for-loop tries to increment the iterator, we get <i>unexpected results<\/i>.<\/p>\n<p>This is a frustrating problem, but it can be solved.  In short you have to:<\/p>\n<ul>\n<li>grab the iterator that is returned from the erase operation<\/li>\n<li>set your loop iterator to that returned iterator<\/li>\n<li>change from a for-loop to a while-loop (to ensure that your loop iterator is not incremented when a task is removed)<\/li>\n<\/ul>\n<p>Here is the modified code:<\/p>\n<p><code><\/p>\n<p>&#160;&#160;TaskIter removeTask(Task* t) {<\/p>\n<p>&#160;&#160;&#160;&#160;TaskIter it = find(mTasks.begin(); mTasks.end(), t);<\/p>\n<p>&#160;&#160;&#160;&#160;if(it != mTasks.end()) { it = mTasks.erase(it); }<\/p>\n<p>&#160;&#160;&#160;&#160;return it;<\/p>\n<p>&#160;&#160;}<\/p>\n<p>&#160;<\/p>\n<p>&#160;&#160;void processQueue() {<\/p>\n<p>&#160;&#160;&#160;&#160;TaskIter loopit = mTasks.begin();<\/p>\n<p>&#160;&#160;&#160;&#160;while(loopit != mTasks.end()) {<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;Task* task = *loopit;<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;if(task->isNotDone()) {<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;task->doSomething();<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;++loopit;<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;}<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;else {<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;loopit = removeTask(task);<\/p>\n<p>&#160;&#160;&#160;&#160;&#160;&#160;}<\/p>\n<p>&#160;&#160;&#160;&#160;}<\/p>\n<p>&#160;&#160;}<\/p>\n<p><\/code><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A short article about removing items from a standard C++ container.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[34,25,11,14],"tags":[],"class_list":["post-411","post","type-post","status-publish","format-standard","hentry","category-c","category-software","category-technology","category-tips"],"_links":{"self":[{"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/posts\/411","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/comments?post=411"}],"version-history":[{"count":0,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/posts\/411\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/media?parent=411"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/categories?post=411"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.codedread.com\/blog\/wp-json\/wp\/v2\/tags?post=411"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}