代码之家  ›  专栏  ›  技术社区  ›  ecneics

向量中的迭代器与指针

  •  0
  • ecneics  · 技术社区  · 3 年前

    有很多其他的方法来处理向量的元素。

    我可以用这样的指针:

    vector<int> v = {10, 11, 12};
    int *p = &v[0];
    cout << *p;    //Outputs "10"
    

    我也可以这样使用指针:

    vector<int> v = {10, 11, 12};
    vector<int>::pointer p = v.data();
    cout << *p;    //Outputs "10"
    

    我也可以使用迭代器类型:

    vector<int> v = {10, 11, 12};
    vector<int>::iterator i = v.begin();
    cout << *i;    //Outputs "10"
    

    我在这里遗漏了什么重要的区别吗?

    0 回复  |  直到 10 年前
        1
  •  12
  •   Joseph Mansfield    10 年前

    就能够完成手头的任务而言,他们都同样出色。毕竟,它们都提供了一个满足迭代器要求的对象,并且您正在使用它们指向 vector . 然而 ,我会选择 vector<int>::iterator 选项,因为类型更能表达我们打算如何使用它。

    原始指针类型, int* ,几乎没有告诉你什么 p 是,但它存储 int .如果你想想 P 孤立地说,它的类型并不能告诉你如何使用它。这个 vector<int>::pointer 选项也有同样的问题——它只是将它指向的对象的类型表示为向量的元素类型。没有理由真的需要指出 矢量

    另一方面 向量<int>::迭代器 告诉你需要知道的一切。它明确表示对象是迭代器,迭代器用于指向 vector<int> .

    如果您碰巧更改了容器类型,这也有更易于维护的好处。如果你换成了 std::list 例如,指针类型将不再工作,因为元素不是作为连续数组存储的。这个 iterator 容器的类型始终为您提供一个类型,您可以使用它来迭代其元素。


    当我们有了概念,我希望最好的实践是:

    ForwardIteratorOf<int> it = std::begin(v);
    

    哪里 ForwardIteratorOf<int> (我想象它的存在)变成了最能描述你的意图的概念 it .如果元素的类型无关紧要,那么 ForwardIterator (或 BidirectionalIterator , RandomAccessIterator ,或其他)。

        2
  •  4
  •   R Sahu    10 年前

    如果您添加支票:

    if ( !v.empty() )
    

    那么,你展示的所有例子都同样有效。

    如果要迭代 vector ,我同意:

    vector<int>::iterator i = v.begin();
    

    使用迭代器检查迭代器是否到达向量的末尾比使用其他形式更容易。

    if ( i != v.end() )
    {
       // Do stuff.
    }
    
        3
  •  0
  •   Ulrich Eckhardt    10 年前

    所有这些方法都有各自的优点,但其核心是非常相似的。但是,当向量为空时,其中一些不起作用(它们会导致所谓的“未定义行为”)。

        4
  •  0
  •   pseudovella    4 年前

    根据 cppreference :

    指向数组元素的指针满足LegacyContiguousIterator的所有要求

    这是最强大的迭代器,因为它包含所有其他迭代器功能。所以它们可以是同一个,迭代器只是使代码清晰、一致和可移植的一种手段。

    例如,我们可以有一些容器“C”。。。

    //template <typename T, int N> class C { //for static allocation
    template <typename T> class C {
        //T _data[N]; //for static allocation
        T* _data; //need to dynamically allocate _data
    public:
        typedef T* iterator;
    }
    

    哪里 C<int>::iterator 会是一个 int* 也不会有什么不同。

    也许我们不想/不需要 LegacyContiguousIterator 所以我们可以重新定义 C<int>::迭代器 作为另一个遵循大纲的课程 LegacyForward迭代器 .这个新的迭代器类可能会重新定义 operator* .在这种情况下,它取决于实现,并且 智力* 尝试访问元素时可能会导致未定义的行为。

    这就是为什么迭代器应该是首选的,但在大多数情况下,它们将是相同的东西。

    在这两种情况下,只要我们定义了所有其他必需的成员函数和typedef,我们的容器“C”就可以像其他STL容器一样工作。