c++stl中的iterator 和 iterator_traits

Posted 胖虎code

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++stl中的iterator 和 iterator_traits相关的知识,希望对你有一定的参考价值。

问题提出

 容器负责数据的存储、算法负责对数据的操作, 而迭代器(可以假想为指针)负责将算法所需要的数据从容器中获取。
 那么问题来了,设计一个Iterator,返回出统一的指针、引用和所需要的操作
并且实现基本的++、*等操作。但是内置的基本类型不具备这些指针、引用等统一类型(接口),这时想到的一个方法是 中间加一层,通过第三方来萃取出他的类型等基本信息。具体实现为模板的偏特化。

目录

  •  迭代器的定义

  •  迭代器的种类

  •  iterator_traits源码

  •  自制迭代器和traits

  •  迭代器实现案例

//对应的源码位置在<iterator>下的
std_iterator_base_types.h文件下

迭代器的定义

template<typename _Category, 
typename _Tp,
typename _Distance = ptrdiff_t,
typename _Pointer = _Tp*,
typename _Reference = _Tp&>
struct iterator
{
/// One of the iterator tag
typedef _Category iterator_category;

/// The type "pointed to" by the iterator.
typedef _Tp value_type;

/// Distance between iterators is represented as this type.
typedef _Distance difference_type;

/// This type represents a pointer-to-value_type.
typedef _Pointer pointer;

/// This type represents a reference-to-value_type.
typedef _Reference reference;
};

 迭代器不含有任何成员,只有数据类型的定义,相应5种类型的统一别名:

iterator_category
value_type
differnece_type
pointer
refernece

 简单解释下就是种类就是前向迭代器还是双向迭代器;
value_type就是对应容器container的模板参数T;
后面的difference_type指的是两个迭代器之间的距离, 就是一个无符号的长整型;
pointer和reference在STL中使用的就很少了。

迭代器的种类

/// Marking input iterators.
struct input_iterator_tag { };

/// Marking output iterators.
struct output_iterator_tag { };

/// Forward iterators support a superset of input iterator operations.
struct forward_iterator_tag : public input_iterator_tag { };

/// Bidirectional iterators support a superset of forward iterator
/// operations.
struct bidirectional_iterator_tag : public forward_iterator_tag { };

/// Random-access iterators support a superset of bidirectional
/// iterator operations.
struct random_access_iterator_tag : public bidirectional_iterator_tag { };

 对应的继承关系可以看到分为输入输出两类。输入<--单向迭代器<--双向迭代器<--随机迭代器

iterator_traits源码

  •  iterator_traits接口

template<typename _Iterator>
struct iterator_traits;
  •  一般实现

template<typename _Iterator>
struct __iterator_traits<_Iterator,
__void_t<typename _Iterator::iterator_category,
typename _Iterator::value_type,
typename _Iterator::difference_type,
typename _Iterator::pointer,
typename _Iterator::reference>>
{
typedef typename _Iterator::iterator_category iterator_category;
typedef typename _Iterator::value_type value_type;
typedef typename _Iterator::difference_type difference_type;
typedef typename _Iterator::pointer pointer;
typedef typename _Iterator::reference reference;
};

template<typename _Iterator>
struct iterator_traits
: public __iterator_traits<_Iterator> { };
  •  偏特化实现指针类型

/// Partial specialization for pointer types.
template<typename _Tp>
struct iterator_traits<_Tp*>
{

typedef random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef ptrdiff_t difference_type;
typedef _Tp* pointer;
typedef _Tp& reference;
};
  •  偏特化实现const pointer

    /// Partial specialization for const pointer types.
    template<typename _Tp>
    struct iterator_traits<const _Tp*>
    {

    typedef random_access_iterator_tag iterator_category;
    typedef _Tp value_type;
    typedef ptrdiff_t difference_type;
    typedef const _Tp* pointer;
    typedef const _Tp& reference;
    };

例子

vector的迭代器种类

std::vector<T> vec;
vec.begin();

iterator
begin() _GLIBCXX_NOEXCEPT
{ return iterator(this->_M_impl._M_start); }

typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator;

template<typename _Iterator, typename _Container>
class __normal_iterator{};

template<typename _Iterator, typename _Container>
class __normal_iterator
{

protected:
_Iterator _M_current;

typedef std::iterator_traits<_Iterator> __traits_type;

public:
typedef _Iterator iterator_type;
typedef typename __traits_type::iterator_category iterator_category;
};

 可见vector是随机迭代器

list迭代器

typedef _Tp					 value_type;
typedef _List_iterator<_Tp> iterator;

template<typename _Tp>
struct _List_iterator
{

typedef _List_iterator<_Tp> _Self;
typedef _List_node<_Tp> _Node;

typedef ptrdiff_t difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
typedef _Tp value_type;
typedef _Tp* pointer;
typedef _Tp& reference;
/*
...
*/

};

 List为双向迭代器

自制迭代器和萃取器

#include <iostream>

//iterator
template<typename T>
class MyIter
{

T * m_data;
public:
MyIter(T * p):m_data(p){;}
T& operator*()const
{ return *m_data;}
typedef T value_type;
};

//iterator_traits
template<typename T>
struct my_traits
{

typedef typename T::value_type value_type;
};
//partial specialization 原生指针
template<typename T>
struct my_traits<T*>
{

typedef T value_type;
};

//const void *带const 指针
template<typename T>
struct my_traits<const T*>
{

typedef T value_type;
};

template<typename Iter>
typename my_traits<Iter>::value_type func(Iter i)
{
std::cout<<"traits the value_type"<<std::endl;
return *i;
}


int main()
{
MyIter<int> my_iter(new int(10));
std::cout<<func(my_iter)<<std::endl;

int * ptr1 = new int(11);
std::cout<<func(ptr1)<<std::endl;

const int * ptr2 = new int(12);
std::cout<<func(ptr2)<<std::endl;
}

第三方源码 file_iterator

问题
  • 边界检查(判断相等)

  • 自增和解引用(重载operator++(), operator*())

 一个包装好的file class拥有对应的iterator

// File class
struct StdFile: public FileOp
{
typedef ifile_iterator iterator;
StdFile();
StdFile(const std::string&, int mode = O_RDONLY);
~StdFile();
operator bool() const;
void open(const std::string&, int mode = O_RDONLY);
void close();
uint read(char*, int);

iterator begin();
iterator end();

};

struct ifile_iterator: public std::iterator<std::input_iterator_tag, char>
{
ifile_iterator();
ifile_iterator(StdFile* f);
ifile_iterator(const ifile_iterator&);
ifile_iterator& operator=(const ifile_iterator&);
~ifile_iterator();
inline ifile_iterator& operator++();
inline ifile_iterator operator++(int);
inline reference operator*();
inline bool operator!=(const ifile_iterator& right) const;
inline bool operator==(const ifile_iterator& right) const;
private:
void cp(const ifile_iterator&);
void setBufsz();
enum { defBufsz = 4096 }; // default buffer size(4 missing getpagesize)
void underflow();
bool m_eof;
value_type* m_buf;
value_type* m_ptr;
int m_count;
StdFile* m_pFile;
unsigned int m_read; //bytes read so far
unsigned int m_bufsz;
};
  •   迭代器的begin和end

StdFile::iterator StdFile::begin()
{
return iterator(this);
}

StdFile::iterator StdFile::end()
{
return iterator();
}
//默认构造函数
ifile_iterator::ifile_iterator()
: m_eof(1), m_buf(0), m_ptr(0), m_count(0), m_pFile(0), m_read(0)
{
setBufsz();
}

//构造函数
ifile_iterator::ifile_iterator(StdFile* pFile)
: m_eof(0), m_buf(0), m_ptr(0), m_count(0), m_pFile(pFile), m_read(0)
{
setBufsz();
if(m_pFile == 0)
{
m_eof = 1;
return;
}
m_ptr = m_buf = new value_type[m_bufsz];
underflow();
}

 不同的是构造函数里面EOF设置为0,而且进行了预读,每次读取一个 getpagesize()的大小,若读取失败(读取到的大小小于等于0),设置EOF为1。且重载迭代器的operator==()。

inline
bool ifile_iterator::operator==(const ifile_iterator& right) const
{
// are equal if both are EOF
return (m_eof && right.m_eof);
}

 这段代码就是我们常看的for(auto a =v.begin(); a !=v.end();++a) 中的判断部分。

  •  迭代器的自增

    postfix

inline
ifile_iterator ifile_iterator::operator++(int)
{
ifile_iterator cp = *this;
operator++();//call prefix
return cp;
}

  prefix

inline
ifile_iterator& ifile_iterator::operator++() // prefix
{
if(--m_count > 0)
++m_ptr;
else
underflow();//预读
return *this;
}


以上是关于c++stl中的iterator 和 iterator_traits的主要内容,如果未能解决你的问题,请参考以下文章

c++stl中的iterator 和 iterator_traits

Iterator和Iteratable的区别,介绍

iteratable iterator generator 初步理解总结

如何使用 reverse_iterator 插入

STL 之 list源码自行实现(iterator)

C++ STL中的 iterator 和 const_iterator