Effective STL Terms 26

zhaozj2021-02-11  245

Terms 26: Try to use Iterator instead of const_iterator, reverse_iterator and const_reverse_iterator

As you know, each standard container class provides four iterator types. For Container , the role of Iterator is equivalent to T *, and const_iterator is equivalent to const t * (you may have seen T const * such a way: they mean [1]). Add an item or const_iterator that allows you to move to the next element of the container in a travers that starts from the pole. Reverse_iterator is equivalent to the corresponding T * and Const T *, which is different, adding the REVERSE_ITERATOR or Const_Reverse_iterator, will move you to the next element of the container in the traversal from the tail to the head.

Let me demonstrate two things. First, look at the style of Vector Insert and ERASE:

Iterator INSERT (Iterator Position, Const T & X);

Iterator Erase;

Iterator ERASE (Iterator Rangeend) and ITERATOR RANGEEND;

Each standard container contains and this almost a function, although the return type is different from the type of container. It should be noted that these methods only accept parameters of the Iterator type, not const_iterator, reverse_iterator or const_reverse_iterator. Always Iterator. Although the container supports four iterator types, one of which has other privileges. That is iterator, iterator is particularly special [2].

I want you to see the second thing is this picture, which shows the conversion relationship between several iterator:

The figure shows the implicit conversion from Iterator to Const_Iterator, from Iterator to Reverse_Iterator and from REVERSE_ITERATOR to Const_Reverse_iterator. And, Reverse_iterator can be converted to Iterator by calling its Base member function. Const_reverse_iterator can also be converted similarly to const_iterator. The fact that cannot be displayed in a picture is: Perhaps it is not what you expected by Base. We will discuss this in detail in terms 28.

You should find that there is no way to convert from a const_iterator to get an Iterator, or you can't get REVERSE_ITERATOR from Const_Reverse_Iiterator. This is very important, because this means if you have a const_iterator or const_reverse_iterator, you will find some member functions of the South to make them with some member functions of the container. Those member functions require iterator, and you cannot get iterator from the Const iterator type. When you need to point out an insertion location or delete element, the Const iterator is almost useless.

Don't be stupid to claim that the const iterator is nothing. No, they can work with the algorithm, because the algorithm usually doesn't care about what the iterator is, as long as it is the appropriate type (category), many containers are also accepting the const iterator. Some of the forms of INSERT and ERASE have some blowing.

I wrote that if you want to point out the inserted location or delete element, the const iterator "almost" is useless. This suggests that it is not completely useless. That is true. If you find a way you can get an Iterator from const_iterator or const_reverse_iterator, then they are useful. It is often possible. However, this method does not always travel, and even if it is feasible, the method is not intuitive, and it is also very lack of efficiency. This topic will be enriched enough to enrich its own terms, so if you are interested in this detail, go to Terms 27. Now, we have enough reason to believe that you should try to use Iterator to replace const or Reverse type iterators: Iterator. If you need to call these functions, you must generate iterator, and you cannot use Const or Reverse Iterators. It is impossible to implicate the const_iterator to iterator, and we will discuss the technology from a const_iterator to generate an Iterator in terms 27 and is not universally applicable, and it is not guaranteed. Iterator, which is converted from Reverse_Iiterator, may require the corresponding adjustment after the conversion, and we will discuss when to adjust and adjust during terms 28.

All of these things can be seen if you try to use the Iterator instead of the Const or Reverse type iterator, allowing the container to make the use of the container easier, more efficient and avoiding potential bugs.

In fact, you might be more faced between Iterator and const_iterator. ITERATOR AND REVERSE_ITERATOR selection is obvious - depending on the traversal of it before or later. You can choose one of you, and even if you choose Reverse_Iterator, you can still get the appropriate Iterator via Base when you want to call the container member function of the Iterator, you can need some adjustments, see Terms 28).

When choosing between Iterator and Const_Iiterator, you have more reasons to choose Iterator, even if const_iterator is equally possible, even if you do not need to call any member functions of the container class. The annoying reason includes comparison between Iterator and Const_ITERATOR. I hope we can all agree that this is reasonable code:

Typedef Deque intdeque; // typef can be greatly simplified

Typedf INTDDEQUE :: item; // STL container class and Iterator

TypedEf INTDEQUE :: const_iterator constiter; // operation.

ITer I;

CONSTITER CI;

... // Same Container

IF (i == Ci) ... // Compare Iterator and Const_Iterator

What we do is only compared between the two iterators in the same container, which is the most basic action in STL. The only change is the type of the equal sign is Iterator, and the type of the other is const_iterator. This should not matter, because Iterator should be implicitly converted into const_iterator before comparing, and the real comparison should be done between two const_iterator.

The case is true for STL implementation for design. But for other implementations, this code cannot even compile. The reason is that these implementations will use const_iterator's operator == as a member function of const_iterator instead of non-member functions. The solution to the problem is very interesting: as long as you exchange two Iterator's position: if (ci == i) ... // is not possible

// By compile time solution

Not only is it compared to equal, as long as you mix Iterator and const_iterator (or Reverse_Iteerator and const_reverse_iterator) in the same expression, this problem may appear. For example, when you try to perform subtraction operation between the two random access iter:

IF (i-ci> = 3) ... // If there is at least three elements between I and CI ...

If the type of iterator is different, your (correct) code may be rejected (incorrectly). You can want to solve the method (swap i and ci position), but this time, not just replace CI-I with I-CI:

IF (CI 3 <= i) ... // When the above code is unable

// By compile time solution

The easiest way to avoid such issues is to reduce the opportunity to mix different types of iterators, in other words, returns to use Iterator instead of consT_iterator. From the perspective of Const Correctness (a very valuable angle), only some of the potential STL achievements (and these drawbacks have a more direct solution) and abandon const_iterator seems to be owed. But consider the adhesive relationship between Iterator and some container members, from practice, CONST_ITERATOR, does not avoid it is difficult to avoid. What's more, sometimes it is not worth the trouble that is involved in Const_Iterator.

[1] About this topic, please refer to "Const T vs. T Const" published on Embedded Systems programming in February 1999, the author is Dan Saks.

[2] The reason for "Iterator is more special" is not clear. The earliest STL implementation of HP contains Itert and Erase with Iterator parameters, and this design problem does not reconsider during standardization. But in the future, this may change because the library workgroup released # 180 records, explained "This problem is considered in the next standard version" (C library problem can be from http: //anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html See)

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

New Post(0)