//迭代器:iterator, const_iterator, reverse_iterator , const_reverse_iterator //流迭代器:istreambuf_iterator和 istream_iterator //它们之间的关系是什么?可以互相转化吗?可以混合使用吗?
/** 解释以下迭代器:container 1, iterator的作用相当于 T,而const_iterator则相当于const T:从容器的开头向尾部的遍历中让你移动到容器的下一个元素 2,reverse_iterator同样相当于T,const_reverse_iterator相当于const T,从尾部向头部移到容器的下一个元素 我有足够的理由让你选择 iterator */
//理由一:inset和erase的实现 //有些标准容器包含了如下函数,只接受iterator类型
iterator insert(iterator position, const T& x);
iterator erase(iterator position);
iterator erase(iterator rangeBegin,iterator rangeEnd);
//貌似验证后不是这样的!!!见 1
//http://c.biancheng.net/view/7196.html
//1
set<int> v = { 1, 2, 3 };
set<int>::const_iterator i;
for (i = v.begin(); i != v.end(); ++i) {
if (i == v.begin()) {
i = v.insert(i, 5);
i = v.erase(i);
}
}
//理由二:几种迭代器之间的转换关系
//iterattor到const_iterator, iterator到reverse和从 reverse_iterator到const_reverse_iterator可以进行隐式转换 //reverse_iterator可以通过base成员函数转换为iterator, const_reverse_iterator也可以类似通过base转换成为const_iterator //但是, 发现 const_iterator无法转换成iterator
//理由三:iterator和const_iterator之间的比较
typedef deque<int> IntDeque;
typedef IntDeque::iterator Iter;
typedef IntDeque::const_iterator ConstIter;
//iterator在比较之前隐式转换成const_iterator , 见2
//2
deque<int> d = {1,2,3};
Iter ii = d.begin();
ConstIter ci = d.begin();
if (ii == ci){
std::cout<<"yes, =="<<std::endl;
}
//注意,以上大多数可以用,但是要避免实现将 const_iteratror的operator==作为const_iterator的一个成员函数而不是非成员函数
//交互位置可以解决,混合使用时候注意,安全映射,将 iterator转换成 const_iterator
if(static_cast<ConstIter>(ii) - ci == 0){
std::cout<<"yes, =="<<std::endl;
}
//不能从 const_itertor转换到iterator 证明见 3
//3
Iter iii(ci);//错误,没有从const_iterator到iterato的隐式转换
Iter iii(const_cast<Iter>(ci));//同上
//原因是两者是完全不同的类,对于 list、set、multiset、map、multimap, deque一样的结果
//如何实现转换呢?见 4
//4
//让ci指向d
Iter i_(d.begin());//初始化i为d.begin()
ConstIter ci_(d.begin() + 1);
advance(i_,distance(i_,ci_));//把i移到指向ci的位置
//理想状态:distance返回两个指向同一个容器的iterator之间的距离;advance则用于将一个iterator移动指定的距离。
//如果i和ci指向同一个容器,那么表达式advance(i, distance(i, ci))会将i移动到与ci相同的位置上
//无法通过编译,但是!
//为什么呢?看下distance的定义,见 4-1
//4-1
template<typename InputIterator>
typename iterator_traits<InputIterator>::difference_type
distance(InputIterator first,InputIterator last);
//编译器会根据使用的实参类型推断出 InputIterator的类型,因此以上例子接受两个不同的类型,调用会失败
//需要显式指明distance调用的模板参数类型, 见 4-2
//4-2
advance(i_,distance<ConstIter>(i_,ci_));
//调用reverse_iterator的base成员函数可以产生“对应的”iterator,但这句话有些辞不达意 //见 5
//5
vector<int> v1;
v1.reserve(5);
for(int i=0; i<5; i++){
v1.push_back(i);
}
//使用 ri指向 3
vector<int>::reverse_iterator ri = std::find(v1.rbegin(), v1.rend(),3);
//使 i和 ri的base一样
vector<int>::iterator i1(ri.base());
//https://www.coder.work/article/1236550
std::cout<<"ri "<<*ri<<" "<<*i1<<std::endl;
//可以看出两者打印的值不同见 图 1
//图1 //可以看出 reverse_iterator和它对应的 base iterator之间特有的偏移量,就像 rbegin()和rend()与相关的begin()和end()一样
//一些函数只允许iterator不允许reverse_iterator,该怎么实现呢?
//假设你在ri指出的位置上把一个新元素插入 v = 99
//ri遍历从右向左,并且插入操作会将新元素插入到 ri位置,将原先ri位置的元素移到编译过程中的下一个位置,因此, 3应该出现在99的左侧
//v1.insert(ri,99); //不能用reverse_iterator
v1.insert(i1,99);
/** 结论: 我们不能用ri来指定插入的地方,因为它不是一个iterator。我们必须用i来代替。如上所述,当ri指向3 时,i(就是ri.base())指向4。如果我们用ri来指定插入位置,那么用i指向插入位置,那个假设就是正确的。 要实现在一个reverse_iterator ri指出的位置上插入新元素,在ri.base()指向的位置插入就行了。对于 insert操作而言,ri和ri.base()是等价的,而且ri.base()真的是ri对应的iterator */
//再来考虑一下删除函数,最初图如下
//如果你要删除ri指向的元素,不能直击用ri,因为 i和ri不是指向的同一个元素,因此,你要删除的是i的前一个元素
// v1.erase(--ri.base());//尝试删除 ri.base()前面的元素
//不好 因为 ri.base()的结果是一个指针
//不能修改函数返回的指针,换一种思考
//不能减少调用base的返回值,就增加reverse_iterator的值,然后再调用base
// v1.erase((++ri).base());
// reverse_iterator的base成员函数返回一个“对应的”iterator的说法并不准确。对于插入操 // 作而言,的确如此;但是对于删除操作,并非如此。当需要把reverse_iterator转换成iterator的时候,有一点非 // 常重要的是你必须知道你准备怎么处理返回的iterator,因为只有这样你才能决定你得到的iterator是否是你需 // 要的。
//https://zhuanlan.zhihu.com/p/76960794
int main()
{
ifstream in_file("data.txt");
ofstream out_file("output_file.txt");
if(!in_file)
{
cout<<"filesopen failed!\n";
return -1;
}
istream_iterator<string> is(in_file); // 自动按照空格分隔
istream_iterator<string> eof;
vector<string> text;
copy(is,eof,back_inserter(text));
sort(text.begin(),text.end());
std::cout<<"............."<<text.size()<<std::endl;
ostream_iterator<string> os(out_file," ");
copy(text.begin(),text.end(),os);
return 0;
}
改进之后:
#include <locale>
struct csv_reader: std::ctype<char> {
csv_reader(): std::ctype<char>(get_table()) {}
static std::ctype_base::mask const* get_table() {
static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask());
rc[','] = std::ctype_base::space;
rc['\n'] = std::ctype_base::space;
rc[' '] = std::ctype_base::space;
return &rc[0];
}
};
int main()
{
ifstream in_file("data.txt");
in_file.imbue(locale(locale(), new csv_reader()));
//下同上
}