{"id":24,"date":"2014-10-28T15:53:08","date_gmt":"2014-10-28T12:53:08","guid":{"rendered":"http:\/\/blog.dmmedia.org\/en\/?p=24"},"modified":"2014-10-29T10:03:37","modified_gmt":"2014-10-29T07:03:37","slug":"frequent-error-while-using-stderase-with-stdremove_if-in-c","status":"publish","type":"post","link":"https:\/\/blog.dmmedia.org\/en\/frequent-error-while-using-stderase-with-stdremove_if-in-c\/","title":{"rendered":"Frequent error while using std::erase with std::remove_if in C++"},"content":{"rendered":"<p>To remove an element from container of type <code>vector<\/code>, <code>string<\/code>, <code>list<\/code> or <code>deque<\/code> we use <code>erase()<\/code> method with an iterator to unneeded element as a parameter.<\/p>\n<p>After some time we do optimize the code or start to use STL algorithm <code>remove_if()<\/code> from the very beginning. Next we add some fancy <code>boost::bind<\/code> stuff for convenience and etc.<\/p>\n<p>And once in a while we have to remove several elements from container instead of one. And it does not matter if it happens in new code, or while extending old. And here many C++ beginners can do the mistake, either but not knowing about it or just lazy enough not to check the <code>erase()<\/code> method documentation. They copy-paste the old code and change only <code>remove_if()<\/code> search condition. But they forget, that if only one argument is passed to <code>erase()<\/code>, it will delete that only element which is that iterator argument pointing to.<\/p>\n<p>If several elements are needed to be removed from the container, there is an overloaded <code>erase()<\/code> method which accepts two iterators , to the start and to the end of the sequence to be removed. When <code>remove_if()<\/code> algorithm is used, it rearranges elements that should not be removed to the beginning of the container, leaving some trash in the end. For example, let&#8217;s have a <code>vector <int><\/code>, containing the following values:<br \/>\n<code>1 2 3 1 2 3 1 2 3<\/code><\/p>\n<p>Then if we call<br \/>\n<code>bool IsTwo (int i) { return (i == 2); }<\/p>\n<p>tstart = remove_if(v.begin(), v.end(), isTwo)<br \/>\n\/\/remove elements with value 2 from the container v<\/code><\/p>\n<p>we&#8217;ll get<br \/>\n<code>1 3 1 3 1 3 ? ? ?<\/code><br \/>\nwhere ? &#8211; is some trash. <code>tstart<\/code> iterator, returned by <code>remove_if()<\/code>, will point to the first trash element, the third from the end in our case. Trash may contain the same values as before calling <code>remove_if()<\/code>, but that&#8217;s not guaranteed. Container size remains unchanged.<\/p>\n<p>So if we write down the whole code which novice works with, we&#8217;ll get the following:<br \/>\n<code>v.erase(remove_if(v.begin(), v.end(), isTwo));<\/code><\/p>\n<p>And <code>erase()<\/code> will remove only the first trash element from the container and will change containers size by one. The contents will be the following:<br \/>\n<code>1 3 1 3 1 3 ? ?<\/code><br \/>\nwhich is obviously wrong and causes unpredictable consequences if working further with this container.<\/p>\n<p>How to avoid that? When developer is not sure in his skills, he is advised to check the documentation, and find out, that if we call <code>erase()<\/code> as follows:<br \/>\n<code>v.erase(remove_if(v.begin(), v.end(), isTwo), v.end());<\/code><br \/>\nall the trash element will be removed from the container.<\/p>\n<p>If the developer (sometimes overly) confident, the tests are always to the rescue. And don&#8217;t be lazy, write tests for border cases as well. In our case we should at least check removing not only single element, but several as well, and don&#8217;t forget to test none elements removal, and even test with empty container.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>To remove an element from container of type vector, string, list or deque we use erase() method with an iterator to unneeded element as a parameter. After some time we do optimize the code or start to use STL algorithm remove_if() from the very beginning. Next we add some fancy boost::bind stuff for convenience and [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[3],"class_list":["post-24","post","type-post","status-publish","format-standard","hentry","category-programming","tag-c"],"_links":{"self":[{"href":"https:\/\/blog.dmmedia.org\/en\/wp-json\/wp\/v2\/posts\/24","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.dmmedia.org\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.dmmedia.org\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.dmmedia.org\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.dmmedia.org\/en\/wp-json\/wp\/v2\/comments?post=24"}],"version-history":[{"count":1,"href":"https:\/\/blog.dmmedia.org\/en\/wp-json\/wp\/v2\/posts\/24\/revisions"}],"predecessor-version":[{"id":25,"href":"https:\/\/blog.dmmedia.org\/en\/wp-json\/wp\/v2\/posts\/24\/revisions\/25"}],"wp:attachment":[{"href":"https:\/\/blog.dmmedia.org\/en\/wp-json\/wp\/v2\/media?parent=24"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.dmmedia.org\/en\/wp-json\/wp\/v2\/categories?post=24"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.dmmedia.org\/en\/wp-json\/wp\/v2\/tags?post=24"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}