[STL] Simulation implementation of reverse iterator

Table of contents

1. Read the source code

2. Build the framework 

3. Iterator operation

operator*() 

operator->()

operator++()

operator--()

operator!=()

4. Implement the reverse iterator of list

5. Implement the reverse iterator of vector

6. Source code sharing

Write at the end:


1. Read the source code

The vector and list we implemented before seem to only implement their forward iterators, so there is a forward direction,

Is there such a thing as a reverse iterator? The answer is yes, so how do we achieve it?

In fact, according to our previous experience, it is enough to implement a copy according to the characteristics of each container.

But when I was reading the source code before, I didn't seem to see the source code implementation. What's going on?

Let's read how the source code of list is done:

We found the reverse iterator of list here, he didn't implement it himself,

Instead, the class template of this reverse_iterator is used directly. What's the matter?

We found the answer in the stl_iterator.h file of the STL source code:

There actually exists such a class, reverse_iterator, can it be said that other containers,

Are you not implementing a reverse iterator yourself, but using this class directly?

Thinking of this, let's take a quick look at the source code of vector:

Did you find out, their calling methods are exactly the same, they are all the same calls,

The types used are their respective iterator types, via template attributes,

Let the compiler instantiate different codes to achieve their respective iterators,

Very ingenious design, only one code, so that the reverse iterators of all containers can be reused,

So how did he achieve it? Let's take a look at the source code of his implementation:

We can see that this is a member variable of the iterator type.

It's still the old rule. After reading the member variables, let's take a look at the core interface implementation.

Let's first look at the overload of ++:

His ++ is to let the original forward iterator perform -- operation, no problem,

Let's look at the overload of -- again:

There is nothing wrong with it, let's take a look at his dereference operation:

This is strange, why is the position obtained by dereferencing the previous position of the original position? 

Then we have to see how the reverse iterators of those containers determine the initial position,

First look at the list:

The begin of the forward iterator is the first position, and the end is the head node of the sentinel position.

But rbegin uses end to initialize the reverse iterator, that is, his position at end (on the sentinel position)

And rend uses begin to initialize the reverse iterator, that is, its position at begin (the first position)

We can also see if the vector looks like this:

It can be seen that this is also the case.

That doesn't seem right. If you use the iterator directly,

There will be problems when dereferencing for the first time: (here I write a pseudo code to feel it)

rit =  rbegin()

while(rit != rend()) {

        cout << *rit << endl; // here's the problem

        rit++;

}

So when the library implements the dereference operator, it dereferences its previous position,

Let me cut it out and take a look:

It’s almost the same now, let’s start to implement it now~

2. Build the framework 

namespace xl {
	template <class Iterator>
	class reverse_iterator {
	private:
		Iterator _it;

	public:
		reverse_iterator(Iterator it)
			: _it(it)
		{}
	};
}

In fact, the frame is just a little bit.

Just write a member variable, write a constructor and it's almost done.

3. Iterator operation

operator*() 

Let's get started directly:

operator*() {
	Iterator tmp = _it;
	return *(--tmp);
}

At this time we encountered some difficulties,

How should we return this value? As before, we need to make it support const type,

Let's take a look at how the source code is implemented:

The reference here has gone through a series of complex operations and then set out,

The operation he uses here is extraction, which is relatively troublesome and involves the specialization of templates.

So we plan to use a more convenient and violent method, which is to pass it directly through the template parameters:

 

Ref operator*() {
	Iterator tmp = _it;
	return *(--tmp);
}

This way the following implementation also solves it:

operator->()

Ptr operator->() {
	return &(operator*());
}

operator++()

Here we will typedef the class name again, because it is too long:

Then come to implement ++: (here I have implemented both pre- and post-position)

self& operator++() {
	--_it;
	return *this;
}

self operator++(int) {
	self tmp = _it;
	--_it;
	return tmp;
}

operator--()

self& operator--() {
	++_it;
	return *this;
}

self operator--(int) {
	self tmp = _it;
	++_it;
	return tmp;
}

operator!=()

Just use the != comparison of the forward iterator directly:

bool operator!=(const self& s) {
	return _it != s._it;
}

4. Implement the reverse iterator of list

typedef reverse_iterator<iterator, const T&, const T*> const_reverse_iterator;
typedef reverse_iterator<iterator, T&, T*> reverse_iterator;

reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const { return reverse_iterator(begin()); }

 Let's test it out:

#include "iterator.h"
#include "list.h"

int main()
{
	xl::list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);

	for (auto e : lt) cout << e << " ";
	cout << endl;

	xl::list<int>::reverse_iterator rit = lt.rbegin();
	while (rit != lt.rend()) {
		cout << *rit << " ";
		++rit;
	}
	cout << endl;

	return 0; 
}

output:

The output is fine~ 

5. Implement the reverse iterator of vector

Exactly the same operation as list (just paste the code directly)

Then we test directly:

void test_vector() {
	xl::vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	for (auto e : v) cout << e << " ";
	cout << endl;

	xl::vector<int>::reverse_iterator rit = v.rbegin();
	while (rit != v.rend()) {
		cout << *rit << " ";
		++rit;
	}
	cout << endl;
}

output:

It turned out to be fine~ 

6. Source code sharing

Simulate Simple STL: Simulate Simple STL (gitee.com)

Write at the end:

The above is the content of this article, thank you for reading.

If you feel that you have gained something, you can give the blogger a like .

If there are omissions or mistakes in the content of the article, please private message the blogger or point it out in the comment area~

Guess you like

Origin blog.csdn.net/Locky136/article/details/131942824