简体   繁体   English

C++ 向量迭代器与指针

[英]C++ vector iterators vs. pointers

There are so many alternative ways of addressing elements of a vector.有很多替代方法来寻址向量的元素。

I could use a pointer like so:我可以像这样使用指针:

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

I could use a pointer this way too:我也可以这样使用指针:

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

I could also use the iterator type:我也可以使用迭代器类型:

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

Are there any significant differences that I'm missing here?我在这里遗漏了任何显着差异吗?

As far as being able to perform the task at hand, they all work equally well.就能够执行手头的任务而言,它们都同样出色。 After all, they all provide an object which meets the requirements of an iterator and you are using them to point at the same element of the vector .毕竟,它们都提供了一个满足迭代器要求的对象,并且您正在使用它们来指向vector的相同元素。 However , I would pick the vector<int>::iterator option because the type is more expressive about how we intend to use it.但是,我会选择vector<int>::iterator选项,因为该类型更能表达我们打算如何使用它。

The raw pointer type, int* , tells you very little about what p is, except that it stores the address of an int .原始指针类型int*很少告诉您p是什么,除了它存储了int的地址。 If you think about p in isolation, its type doesn't tell you very much about how you can use it.如果你单独考虑p ,它的类型并不能告诉你如何使用它。 The vector<int>::pointer option has the same issue - it just expresses the type of the objects it points at as being the element type of a vector. vector<int>::pointer选项也有同样的问题——它只是将它指向的对象的类型表示为向量的元素类型。 There's no reason it actually needs to point into a vector .没有理由它实际上需要指向vector

On the other hand vector<int>::iterator tells you everything you need to know.另一方面, vector<int>::iterator告诉你你需要知道的一切。 It explicitly states that the object is an iterator and that iterator is used to point at elements in a vector<int> .它明确指出该对象是一个迭代器,并且该迭代器用于指向vector<int>元素。

This also has the benefit of being more easily maintainable if you ever happen to change the container type.如果您碰巧更改容器类型,这还具有更易于维护的好处。 If you changed to a std::list , for example, the pointer type just wouldn't work any more because the elements are not stored as a contiguous array.例如,如果您更改为std::list ,则指针类型将不再起作用,因为元素未存储为连续数组。 The iterator type of a container always provides you with a type you can use to iterate over its elements.容器的iterator类型始终为您提供可用于迭代其元素的类型。


When we have Concepts, I'd expect the best practise to be something like:当我们有了概念时,我希望最佳实践是这样的:

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

where ForwardIteratorOf<int> (which I am imagining exists) is changed to whatever concept best describes your intentions for it .其中ForwardIteratorOf<int> (这我想象的存在)改为无论概念最能说明你的意图it If the type of the elements doesn't matter, then just ForwardIterator (or BidirectionalIterator , RandomAccessIterator , or whatever).如果元素的类型无关紧要,那么只需ForwardIterator (或BidirectionalIteratorRandomAccessIterator或其他)。

If you add the check:如果添加检查:

if ( !v.empty() )

Then, all the example you've shown are equally valid.那么,您展示的所有示例都同样有效。

If you are about to iterate over the elements of the vector , I would go with:如果您要遍历vector的元素,我会选择:

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

It's easier to check whether the iterator has reached the end of the vector with an iterator than with the other forms.使用迭代器比使用其他形式更容易检查迭代器是否已经到达向量的末尾。

if ( i != v.end() )
{
   // Do stuff.
}

All these ways have their advantages, but at the core they are very similar.所有这些方式都有其优点,但在核心它们非常相似。 Some of them don't work though (they cause so-called "undefined behaviour") when the vector is empty.当向量为空时,其中一些不起作用(它们会导致所谓的“未定义行为”)。

According to cppreference :根据cppreference

A pointer to an element of an array satisfies all requirements of LegacyContiguousIterator指向数组元素的指针满足 LegacyContiguousIterator 的所有要求

which is the most powerful iterator as it encompasses all other iterators functionality.这是最强大的迭代器,因为它包含所有其他迭代器功能。 So they can be one and the same, an iterator is just a means of making our code clear, consice and portable.所以它们可以是相同的,迭代器只是使我们的代码清晰、简洁和可移植的一种手段。

For example we could have some container "C"...例如,我们可以有一些容器“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;
}

where C<int>::iterator would be an int* and there would be no difference.其中C<int>::iterator将是int*并且没有区别。

Maybe we don't want/need the full power of a LegacyContiguousIterator so we could redefine C<int>::iterator as another class that follows the outline for say LegacyForwardIterator .也许我们不想要/不需要LegacyContiguousIterator的全部功能,因此我们可以将C<int>::iterator重新定义为遵循LegacyForwardIterator大纲的另一个类。 This new iterator class may redefine operator* .这个新的迭代器类可以重新定义operator* In this case it is implementation dependant and an int* may cause undefined behaviour when trying to access the elements.在这种情况下,它依赖于实现,当尝试访问元素时int*可能会导致未定义的行为。

This is why iterators should be preferred but in most cases they are going to be the same thing.这就是为什么迭代器应该是首选的原因,但在大多数情况下,它们将是相同的。

In both cases our container " C" will work just like other STL containers so long as we define all the other necessary member functions and typedefs.在这两种情况下,只要我们定义所有其他必要的成员函数和 typedef,我们的容器“C”就会像其他 STL 容器一样工作。

There are so many alternative ways of addressing elements of a vector.解决向量元素的方法有很多。

I could use a pointer like so:我可以这样使用指针:

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

I could use a pointer this way too:我也可以这样使用指针:

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

I could also use the iterator type:我也可以使用迭代器类型:

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

Are there any significant differences that I'm missing here?我在这里缺少什么明显的区别吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM