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