[C++]高效使用迭代器的一些建议

迭代器

本文介绍四种迭代器的使用细节,已经相互转换的方法,从而提高对迭代的理解和使用。

1. iterator优于const_iterator, const_reverse_iterator, reverse_iterator

iterator几乎可以适用于所有需要迭代器为参数的函数调用。但其他的三种迭代却不一定。

以下这张图可以清晰地表明不同迭代器之间的转换关系。

我们需要知道的是,有些版本的insert和erase是没有给出const_iterator的重载版本的,所以如果要在相应位置做操作就必须把他们转换为iterator才能进行。请注意,不要考虑强制类型转换,这总是不太好的选择。后面我们将给出转换的方法。

2. const_iterator转换为iterator

之前提到,不要考虑强制类型转换,是因为这两个类型是完全不同的类型!(对vector和string可能不适用)所以把两个完全不同的类型相互转换是非常没有道理的。

(在vector和string里,迭代器会被实现为T* 和 const T*,他们之间是可以进行隐式类型转换的。)

所以,我们希望得到一种更加普遍可用的方法。

这里我们需要使用两个成员函数来解决这个问题。

#include 
#include 
#include 
using namespace std;
int main() {
    typedef deque<int> intDeq;
    typedef intDeq::iterator iter;
    typedef intDeq::const_iterator citer;
    intDeq d;
    citer ci;
    iter i(d.begin());
    advance(i, distance(i, ci));
    return 0;
}

这里需要注意的是不能直接调用distance函数。正如我们前面说的,iterator和const_iterator是两个不一样的类型,所以必须给出确定的类型来做比较。

效率上来说,这种方法对于随机访问的容器是常数时间操作,对于双向迭代器来说是线性时间操作。所以效率上来说是不太好的。

3. 正确理解reverse_iterator的base函数

base函数并不是真正的把reverse_iterator转换iterator, 其中还有一个偏移量的问题。

这是base调用的偏移量。

因为reverse本来就是从右往左遍历,所以插入的操作理所应当在iter的右边,所以insert操作和我们预想的结果是一样的。

但是对于erase则不是这样的。因为base会自动往右移一个偏移量,所以我们需要修正这个编译量,例如,而这很简单。

    v_i.erase((++iter).base());

4. istreambuf_iterator来作为字符的输入

除了传统的使用文件操作的方法,我们还可以使用迭代器来实现读取文件内容。

通过设定dataFile.unsetf(ios::skipws);,我们可以实现忽略空格的输入。

#include 
#include 
using namespace std;
int main() {
    fstream dataFile("data.txt");
    string str((istream_iterator<char>(dataFile)), istream_iterator<char>());
    dataFile.unsetf(ios::skipws);
    copy(str.begin(), str.end(), ostream_iterator<char>(cout));
    return 0;
}

但更简单的说法是:

#include 
#include 
using namespace std;
int main() {
    fstream dataFile("data.txt");
    string str((istreambuf_iterator<char>(dataFile)), istreambuf_iterator<char>());
    copy(str.begin(), str.end(), ostream_iterator<char>(cout));
    return 0;
}

你可能感兴趣的:(C++编程)