dim*_*imm 21 c++ iterator vector stdvector
只需一点介绍,简单的单词.在C++中,迭代器是"事物",你可以在其上至少编写解引用运算符*it,增量运算符++it,对于更高级的双向迭代器,减量--it,最后但并非最不重要的是,对于随机访问迭代器,我们需要运算符索引it[]和可能的加法和减法.
C++中的这类"东西"是具有相应运算符重载的类型的对象,或简单和简单的指针.
std::vector<>是一个包装连续数组的容器类,因此指针作为迭代器是有意义的.在网上,在一些文献中你可以找到vector.begin()用作指针.
使用指针的基本原理是开销更少,性能更高,特别是如果优化编译器检测到迭代并执行其操作(向量指令和内容).使用迭代器可能更难以使编译器进行优化.
知道这一点,我的问题是为什么现代STL实现,比如Mingw 4.7中的MSVC++ 2013或libstdc ++,为矢量迭代器使用了一个特殊的类?
Wal*_*ter 21
你vector::iterator可以通过一个简单的指针实现完全正确(参见这里) - 实际上迭代器的概念是基于指向数组元素的指针.对于其他容器,如map,list或deque,然而,指针不会在所有的工作.那为什么不这样做呢?以下是为什么类实现比原始指针更可取的三个原因.
将迭代器实现为单独的类型允许额外的功能(超出标准所要求的范围),例如(在Quentins注释之后的编辑中添加)在解除引用迭代器时添加断言的可能性,例如,在调试模式下.
重载决策如果迭代器是一个指针T*,它可以作为有效参数传递给函数T*,而迭代器类型是不可能的.因此,制作std::vector<>::iterator指针实际上会改变现有代码的行为.例如,考虑一下
template<typename It>
void foo(It begin, It end);
void foo(const double*a, const double*b, size_t n=0);
std::vector<double> vec;
foo(vec.begin(), vec.end()); // which foo is called?
Run Code Online (Sandbox Code Playgroud)依赖于参数的查找(ADL;由juanchopanza指出)如果进行非限定调用,ADL确保namespace std仅在参数是在中定义的类型时才搜索函数namespace std.所以,
std::vector<double> vec;
sort(vec.begin(), vec.end()); // calls std::sort
sort(vec.data(), vec.data()+vec.size()); // fails to compile
Run Code Online (Sandbox Code Playgroud)
std::sort如果vector<>::iterator只是指针,则找不到.
迭代器的实现是实现定义的,只要满足标准的要求即可.它可能是一个指针vector,可以工作.不使用指针有几个原因;
如果所有迭代器都是指针,则++ita map不会将其递增到下一个元素,因为内存不需要是不连续的.过去std:::vector大多数标准容器的连续内存需要"更智能"的指针 - 因此迭代器.
迭代器的物理要求dove-tail非常好,逻辑要求元素之间的移动是一个定义好的"成语"迭代它们,而不仅仅是移动到下一个存储位置.
这是STL的原始设计要求和目标之一; 容器之间的正交关系,算法和通过迭代器连接两者.
既然它们是类,您可以添加一大堆错误检查和完整性检查来调试代码(然后删除它以获得更优化的发布代码).
鉴于基于类的迭代器带来的积极方面,为什么应该或者不应该只使用std::vector迭代器指针- 一致性.早期的实现std::vector确实使用了普通指针,你可以使用它们vector.一旦你必须使用其他迭代器的类,给定它们带来的积极因素,应用它vector成为一个好主意.
因为 STL 的设计理念是,您可以编写一些在迭代器上进行迭代的内容,无论该迭代器是否只是相当于指向内存连续数组元素的指针(如std::array或std::vector)或类似链接列表、一组密钥,在访问时动态生成的东西等。
另外,不要被愚弄:在向量情况下,取消引用可能(没有调试选项)只是分解为内联指针取消引用,因此编译后甚至不会有开销!