C++17 STL Cookbook
上QQ阅读APP看书,第一时间看更新

How it works...

The quick_remove_at function removes items pretty quickly without touching too many other items. It does this in a relatively creative way: It kind of swaps the actual item,  which shall be removed with the last item in the vector. Although the last item has no connection to the actually selected item, it is in a special position: Removing the last item is cheap! The vector's size just needs to be shrunk down by one slot, and that's it. No items are moved during that step. Have a look at the following diagram which helps imaging how this happens:

Both the steps in the recipe code look like this:

v.at(idx) = std::move(v.back());
v.pop_back();

This is the iterator version, which looks nearly identical:

*it = std::move(v.back());
v.pop_back();

Logically, we swap the selected item and the last one. But the code does not swap items, it moves the last one over the first one. Why? If we swapped the items, then we would have to store the selected item in a temporary variable, move the last item to the selected item, and then store the temporary value in the last slot again. This seems useless, as we are just about to delete the last item anyway.

Ok, fine, so the swap is useless, and a one-way overwrite is a better thing to do. Having seen that, we can argue that this step could also be performed with a simple *it = v.back();, right? Yes, this would be completely correct, but imagine we stored some very large strings in every slot, or even another vector or map--in that situation, that little assignment would lead to a very expensive copy. The std::move call in between is just an optimization: In the example case of strings, the string item internally points to a large string in the heap. We do not need to copy that. Instead, when moving a string, the destination of the move gets to point at the string data of the other. The move source item is left intact, but in a useless state, which is fine because we are removing it anyway.