STL: Best practices for removing elements from containers

Speak up first

Perhaps the designers of STL believe that the consistency of the API is very important, the short and beautiful function name is very important, and the human brain capacity is not important ...

Container classification

  • Continuous memory containers (vecotr, deque, queue, string)
  • list (yes, you are the same fireworks)
  • Standard associative containers (set, multiset, map, multimap)

Continuous memory container

First, make two points clear:

  1. Remove here means The std :: remove function is similar to remove_if. Instead of std :: list :: remove, the latter will be mentioned later.
  2. In addition, the delete single-element version and the delete interval version of erase will return the iterator of the next element of the deleted element / interval, because erase will invalidate the iterator of all elements in the subsequent position.

No iteration deletion: remove / remove_if cooperate with erase

Because the design of the STL algorithm module is decoupled from the specific container type, that is, it only receives and operates the iterators of various types of containers, and the iterator hides the specific details of the element iteration in the container, so std: : remove can't really delete the element , because it only knows the iterator of the container, and doesn't know the erase method of the container at all.
For continuous memory containers, the behavior of std :: remove and std :: remove_if is to move all eligible elements to the end of the container and return the iterator of the first element to be deleted. At this time, these elements can be truly deleted by the erase method . The sample code is as follows:

vector<int> vi{1,2,2,3,4,5,6,6};
vi.erase(remove(vi.begin(), vi.end(), 2), vi.end()); // 不使用erase的返回值
vi.erase(remove_if(vi.begin(), vi.end(), [](int i){  // 不使用erase的返回值
    return i > 4;            
}), vi.end());

Iterative deletion: What if you want to delete an element and do something else?

Naturally, it's easy to think of deleting with erase. But for the continuous memory container, after calling erase to delete a single element to invalidate the iterator of the subsequent element (of course, the deleted one also fails), the loop is still running, and the deleted invalidated iterator is added again, and the behavior is undefined. So use the return value of erase:

vector<int> vi{1,2,2,3,4,5,6,6};
for(auto iter = vi.begin(); iter != vi.end(); /*这里啥也不干*/)
{
    if(*iter == 2)
    {
        iter = vi.erase(iter); //这里隐含了一次++
    }
    else
    {
        ++iter;
    }
}

list

List uses continuous memory container for interval deletion and iterative deletion, but it is more efficient to call the list :: remove () function directly , because for the linked list, it is too wasteful to throw all the values ​​to be deleted and then delete them uniformly. , Deleting a single element in the linked list is O (1).

I always feel that STL is a bit over-designed here ... (escape

Guess you like

Origin www.cnblogs.com/jo3yzhu/p/12705988.html