{"id":744,"date":"2017-11-26T23:04:39","date_gmt":"2017-11-27T07:04:39","guid":{"rendered":"http:\/\/wonghoi.humgar.com\/blog\/?p=744"},"modified":"2021-10-29T00:06:27","modified_gmt":"2021-10-29T08:06:27","slug":"oversimplified-getting-rid-of-data-in-stl-containers","status":"publish","type":"post","link":"https:\/\/wonghoi.humgar.com\/blog\/2017\/11\/26\/oversimplified-getting-rid-of-data-in-stl-containers\/","title":{"rendered":"Oversimplified: Getting rid of data in STL containers"},"content":{"rendered":"\n<p>Unless deleting a known range of elements directly through iterators (no conditions to match), which <strong>range<\/strong>&#8211;<code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">erase()<\/code> method can be used directly, targeting specific key\/value\/predicate requires understanding of the container&#8217;s underlying data structure.<\/p>\n\n\n\n<p>I&#8217;d like to give a summary of Item#9 in &#8220;Effective STL&#8221; by defining the names and concepts so the complicated rules can be sensibly deduced by a few basic facts.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>The words &#8216;<em>remove<\/em>&#8216; and &#8216;<em>erase<\/em>&#8216; has very specific meaning for STL that are not immediately intuitive.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>&nbsp;<\/td><td>Lives in<\/td><td>Target to match<\/td><td>Purpose<\/td><\/tr><tr><td><code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">remove_?()<\/code><\/td><td><code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">&lt;algorithm&gt;<\/code><\/td><td>required<\/td><td><strong>Rearrange<\/strong> wanted elements to front<\/td><\/tr><tr><td><code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">erase()<\/code><\/td><td>container<\/td><td>not accepted<\/td><td><strong>Blindly<\/strong> deleting range\/position given<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>There is a <code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">remove()<\/code> method for lists, which is an old STL naming inconsistency (they should have called it erase() like for associative containers). Treat it as a historical mistake.<\/p>\n\n\n\n<p>The usage is easy to remember once you understand it with the right wording above:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>algorithm + container<\/td><td>contiguous<\/td><td>lists<\/td><td>associative<\/td><\/tr><tr><td><code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">remove_?()<\/code>: <em>move front<\/em><\/td><td>Step 1<\/td><td><del>Step 1<br><\/del>(Use <code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">remove_?()<\/code> <strong>method<\/strong>)<\/td><td><em>unordered<\/em>*: cannot rearrange<br>(Use <code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">erase(key)<\/code>&nbsp;directly)<\/td><\/tr><tr><td><code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">erase()<\/code>: <em>trim tail<\/em><\/td><td>Step 2<\/td><td><del>Step 2<br><\/del>(Use <code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">remove_?()<\/code> <strong>method<\/strong>)<del><br><\/del><\/td><td><del>Use after <code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">find_?()<\/code><\/del><br>(Use <code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">erase(key)<\/code>&nbsp;directly)<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Note that there are two steps for sequential (contiguous+lists) containers , hence the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Erase%E2%80%93remove_idiom\">erase-remove idiom<\/a>. It&#8217;s really two steps:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">auto tail = remove(c.begin(), c.end(), T); \nc.erase(tail, c.end());<\/pre>\n\n\n\n<p>but they can be combined in one line since the tail is only useful at one place. Hence<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">c.erase( remove(c.begin(), c.end(), T), c.end() ); <\/pre>\n\n\n\n<p>Lists provides a efficient shortcut method (see table below) since linked-lists does not need to be rearranged (just short the pointers).<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>one-shot&nbsp;methods<\/td><td>contiguous<\/td><td>lists<\/td><td>associative<\/td><\/tr><tr><td>by content<\/td><td>N\/A: use <code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">erase-remove<\/code> idiom<\/td><td><code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">remove(T)<\/code><\/td><td><code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">erase(key)<\/code><\/td><\/tr><tr><td>by predicate<\/td><td>N\/A: use <code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">erase-remove_if<\/code> idiom<\/td><td><code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">remove_if(pred)<\/code><\/td><td>N\/A:&nbsp;Use for-loops for now<br>No erase_if() yet as of C++17.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Never try range-based <code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">remove_?()<\/code> for associative containers. It is a data corruption trap if any attempt is made to use anything named <code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">remove<\/code> on associative containers.<\/p>\n\n\n\n<p>The trap used to be possible since <code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">&lt;algorithms&gt;<\/code> and containers were separate, but <a href=\"http:\/\/en.cppreference.com\/w\/cpp\/algorithm\/remove\">newer C++<\/a> protects you from the trap by checking if the element you are moving is of a <em>MoveAssignable<\/em> type. Since associative containers&#8217; keys cannot be modified (without a rescan), the elements are not <em>move-assignable<\/em>.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>As for erasing through for-loops (necessary if you want to sneak in an extra step while iterating), C++11 now returns an <em>iterator following the last erased element<\/em> uniformly across <strong>all<\/strong> containers. This helps to preserve the running iterator that gets invalidated immediately after the erase through <code class=\"EnlighterJSRAW\" data-enlighter-language=\"cpp\">i=c.erase(i);<\/code><\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>* For brevity, I twisted the term&nbsp;<em>unordered<\/em> here to mean that the native (implementation) data order is dependent on the data involved.<\/p>\n\n\n\n<p>When I said &#8216;cannot rearrange&#8217;, I meant &#8216;cannot efficiently rearrange&#8217;, since there are no cheap O(1) next() or prev() traversal.<\/p>\n\n\n\n<p>It&#8217;s a mess to simply copy one element over another (during rearrangement), leaving orphans there, and re-balance a BST or re-hash a hash-map. Nobody wants to go through such pains to remove element when there are tons of more direct ways out there.<\/p>\n<div class=\"pvc_clear\"><\/div><p id=\"pvc_stats_744\" class=\"pvc_stats all  \" data-element-id=\"744\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/wonghoi.humgar.com\/blog\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p><div class=\"pvc_clear\"><\/div>","protected":false},"excerpt":{"rendered":"<p>Unless deleting a known range of elements directly through iterators (no conditions to match), which range&#8211;erase() method can be used directly, targeting specific key\/value\/predicate requires understanding of the container&#8217;s underlying data structure. I&#8217;d like to give a summary of Item#9 &hellip; <a href=\"https:\/\/wonghoi.humgar.com\/blog\/2017\/11\/26\/oversimplified-getting-rid-of-data-in-stl-containers\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_744\" class=\"pvc_stats all  \" data-element-id=\"744\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/wonghoi.humgar.com\/blog\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p>\n<div class=\"pvc_clear\"><\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[25,6,29],"tags":[],"class_list":["post-744","post","type-post","status-publish","format-standard","hentry","category-cpp","category-note-to-self","category-programming"],"_links":{"self":[{"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/posts\/744","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/comments?post=744"}],"version-history":[{"count":23,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/posts\/744\/revisions"}],"predecessor-version":[{"id":3004,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/posts\/744\/revisions\/3004"}],"wp:attachment":[{"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/media?parent=744"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/categories?post=744"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wonghoi.humgar.com\/blog\/wp-json\/wp\/v2\/tags?post=744"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}