繁体   English   中英

C++ 向量迭代器与指针

[英]C++ vector iterators vs. pointers

有很多替代方法来寻址向量的元素。

我可以像这样使用指针:

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"

我在这里遗漏了任何显着差异吗?

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

原始指针类型int*很少告诉您p是什么,除了它存储了int的地址。 如果你单独考虑p ,它的类型并不能告诉你如何使用它。 vector<int>::pointer选项也有同样的问题——它只是将它指向的对象的类型表示为向量的元素类型。 没有理由它实际上需要指向vector

另一方面, vector<int>::iterator告诉你你需要知道的一切。 它明确指出该对象是一个迭代器,并且该迭代器用于指向vector<int>元素。

如果您碰巧更改容器类型,这还具有更易于维护的好处。 例如,如果您更改为std::list ,则指针类型将不再起作用,因为元素未存储为连续数组。 容器的iterator类型始终为您提供可用于迭代其元素的类型。


当我们有了概念时,我希望最佳实践是这样的:

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

其中ForwardIteratorOf<int> (这我想象的存在)改为无论概念最能说明你的意图it 如果元素的类型无关紧要,那么只需ForwardIterator (或BidirectionalIteratorRandomAccessIterator或其他)。

如果添加检查:

if ( !v.empty() )

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

如果您要遍历vector的元素,我会选择:

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

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

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

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

根据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>::iterator重新定义为遵循LegacyForwardIterator大纲的另一个类。 这个新的迭代器类可以重新定义operator* 在这种情况下,它依赖于实现,当尝试访问元素时int*可能会导致未定义的行为。

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

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

解决向量元素的方法有很多。

我可以这样使用指针:

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"

我在这里缺少什么明显的区别吗?

暂无
暂无

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

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