Effective STL Terms 28

zhaozj2021-02-11  261

Terms 28: Learn how to get Iterator through Reverse_Iterator

The Base member function called Reverse_iterator can generate "corresponding" Iterator, but this sentence is not intended. For example, look at this code, we first put it from the numbers 1-5 into a vector, then generate a Reverse_iterator pointing 3, and initializes an Iterator: BASE by Reverse_Iiterator:

Vector v;

v.reserve (5); // See Terms 14

For (int i = 0; i <5; i) {// insert 1 to 5 to Vector

v.push_back (i);

}

Vector :: reverse_iterator ri = // Make RI points 3

Find (v.rbegin (), v.rend (), 3);

Vector :: Iterator i (ri.base ()); // Like I and Ri's BASE

After performing the above code, you can think of the result is like this:

This picture is very good, showing REVERSE_ITERATOR and its corresponding Base Iterator, just like Rbegin () and rend (), like related begin () and end (), but did not say it. All what you need to know. In particular, it does not explain how to implement the operation you want to complete on the RI. As explained in terms 26, some containers' member functions only accept parameters of the Iterator type, so if you want to insert a new element in the position referred to in Ri, you can't do it directly, because the vector's INSERT function does not accept Reverse_iterator. If you want to delete the elements in the position indicated by Ri, there will be the same problem. The ERASE member function refuses to REVERSE_ITERATOR, insist on the Iterator. In order to complete the deletion and some form of insertion operation, you must first convert the REVERSE_ITERATOR to Iterator first through the base function, then use Iterator to complete the work.

Let us first assume that you want to insert a new element into V at the position pointed out in RI. Special, we assume that the value you want to insert is 99. Remember that the order of RI traversed in the above figure is to left, and insertion operations insert the new element into the Ri position, and move the element of the original RI position to the "next" position of the traversal process, we think 3 should The left side of 99 appears. After inserting the operation, V looks like this:

Of course, we can't use RI to specify where the insert is inserted because it is not an item. We must use I instead. As described above, when Ri points to 3, i (that is, ri.base ()) points 4. If we use ri to specify the insertion position, then point to the insertion position, that hypothesis is correct. Conclusion?

To implement a new element in a location indicated by a Reverse_iterator Ri, you will insert it in the position where ri.base () points to. For INSERT operations, ri and ri.base () are equivalent, and ri.base () is really Ri corresponding to Iterator.

Now consider the situation of deleting elements. Looking back at the initial VECTOR (that is, before inserting 99) RI and I:

If you want to delete the elements pointing to the Ri, you can't use i directly, because i and ri does not point to the same element. Therefore, you have to delete the previous elements of i.

To implement a Reverse_iterator Ri, delete an element, you should delete the former elements of ri.base (). For deletion operations, ri and ri.base () do not equivalence, and ri.base () is not the Iterator corresponding to RI. We still need to look at the code to delete the operation, because it is quite surprising.

Vector v;

... // Insert 1 to 5 to V,

VECOT :: Reverse_iterator ri =

Find (v.rbegin (), v.rend (), 3); //, RI point 3

v.rase (- ri.base ()); // Try to delete the elements in front of Ri.Base ();

// For Vector, in general, compilation does not pass

This design does not have any problems. Expression - Ri.Base () does point out the elements we need to delete. Moreover, they can handle all other containers other than Vector and String. It may also handle Vector and String, but for most vector and string implementations, it cannot be compiled. Under such implementations, Iterator (and const_iterator) will be implemented with built-in pointers, so the result of ri.base () is a pointer.

C and C specify the pointer returned directly to the function, so the iterator of String and Vector is on the STL platform of the pointer, and the expression like -ri.base () cannot be compiled. To transplant the elements from a location indicated by Reverse_iterator, you should try to avoid modifying the return value of Base. no problem. If you can't reduce the return value of calling Base, you only need to add the value of the Reverse_iterator, then call Base!

... //

v.rase (( ri) .base ()); // Delete the element pointing to the Ri;

// This is no problem in compilation!

Because this method applies to all standard containers, this is the preferred technique when deleting a referuation pointed by Reverse_iterator.

It is already very clear that the REVERSE_ITERATOR's BASE member function returns a "corresponding" Iterator's statement that is not accurate. This is true for insertion operations; however, for deleting operations. One thing is a little important when you need to convert Reverse_iterator to iTerator, you must know how you are going to deal with Iterator, because only this can determine if the iTerator you get is what you need.

转载请注明原文地址:https://www.9cbs.com/read-4756.html

New Post(0)