“&vector[0]”和“vector.begin()”有什么区别?它们在IT技术中的应用是什么?

7
这个问题与effective stl书籍的第16项有关,该项规定在遗留代码中使用vector(假设为vector<int>vec)而不是数组时,我们必须使用&vec[0]而不是vec.begin():
 void doSomething(const int* pInts, size_t numlnts);  
 dosomething(&vec[0],vec.size()); \\correct!! 
 dosomething(vec.begin(),vec.size()); \\ wrong!! why??? 

这本书指出,vec.begin()不同于&vec[0]。为什么?它们之间有什么区别?

4
vector::begin() 产生一个迭代器,&vec[0] 产生一个指针。两者并不相同。 - Hans Passant
但是迭代器不就是一个指针吗? - Saksham
指针是迭代器的一种类型,但还有许多其他类型的迭代器并不是指针。尽管通常使用相同的术语,例如,当引用解除引用迭代器时得到的对象时,通常会说迭代器“指向”某个东西。 - Benjamin Lindley
1
@AyushChaurasia:不。 - Lightness Races in Orbit
3个回答

4

std::vector 是一个封装动态大小数组的序列容器。使用它可以方便地存储一堆元素,无需过多关注管理元素存储的底层数组。使用这些类的好处之一是它们提供了许多方法,让你能够处理序列而无需处理原始指针,迭代器就是其中之一。

&vec[0]是指向 vector 使用的底层存储的第一个元素的指针。 vec.begin()是一个迭代器,从向量开头开始。虽然两者都为你提供了一种访问序列中元素的方式,但这是两个不同的概念。搜索迭代器以更好地了解其工作原理。

如果你的代码支持迭代器,那么使用迭代器迭代数据通常是最简单的。部分原因是迭代器不是指针,它们允许您在不需要了解正在迭代的数据结构的实现细节的情况下迭代数据结构的元素。

但是有时您需要原始的数组,例如在某些旧的API或调用C代码中,您可能需要传递一个指向数组的指针。在这种情况下,您别无选择,只能从 vector 中提取出原始数组,可以使用诸如&vec[0]之类的方法。请注意,如果您的编译器支持c++11,则可以明确地使用std::vector::data来执行此操作,该方法将让您访问底层存储数组。c++11方法还具有更清晰地表达您意图的附加好处,方便阅读者阅读您的代码。


它们并不是。将迭代器视为指针的包装器(类)。你不能像那样取一个类对象的地址。类(迭代器)提供了功能,使您可以像使用指针一样使用它们。 - Ajay
1
"请问迭代器和指针有什么区别?" "<迭代器和指针的区别>" "但是迭代器和指针不是一样的吗?" 什么 - Lightness Races in Orbit

4

严格来说,一个产生迭代器,另一个产生指针,但我认为主要区别在于,如果向量为空,vec[0] 会出错,而 vec.begin() 不会。


即使是空数组,取vec[0]的地址也是合法的。你可以指向数组末尾的下一个元素,但不能对该指针进行解引用操作。 - b4hand
1
@b4hand 这对于数组是正确的,但OP特别提到它是一个向量,是吗?我有什么遗漏了吗? - Ami Tavory
1
@b4hand std::vector 不是一个数组。vector::operator[] 返回一个引用,必须绑定到实际对象上。(或者使用序列容器要求:vector::operator[] 必须表现得像对迭代器进行间接寻址一样。) - dyp
@dyp:我认为他可能在引用那个老掉牙的“&a[n]是安全的,因为&*会抵消”的废话。 - Lightness Races in Orbit
非常晚回复一个旧评论,但是是的,我只是在谈论一个数组,所以那个评论在上下文中是不正确的。vec[0]对于一个空数组是合法的,而对于一个空向量则是不合法的。如果你说"vec[0]在向量为空时会导致未定义的行为",那么这可能是一个更好的答案。具体来说,我会为此点赞,因为它添加了其他答案没有提到的信息。 - b4hand

3

vec.begin()的类型是std::vector<int>::iterator&vec[0]的类型是指向std::vector<int>::value_type的指针。它们不一定是同一种类型。

一个实现可能使用指针作为向量的迭代器实现,但这并不是保证的,因此您不应该依靠这种假设。事实上,大多数实现都提供了封装迭代器类型。

关于指针是否可以作为迭代器的问题,这部分是正确的。指针确实符合随机访问迭代器的标准,但并不是所有迭代器都是指针。而且有些迭代器不支持指针的随机访问行为。


这些不一定是相同的类型。据我所知,它们从来不是相同的类型(即使std::vector<T>::iterator仅仅是T*的包装器,它仍然是不同的类型)。 - 463035818_is_not_a_number
1
std::vector<T>::iterator 可能只是 T* 的别名,因此它们是相同的类型。我相信最初的 STL 是使用这种方法构建的;尽管现代几乎所有的实现都使用包装类。 - b4hand
你是对的,我需要阅读一些内容才能说服自己,但再次证明我的知识还不够充分。;) - 463035818_is_not_a_number

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接