通过指针vs end()访问std :: vector元素

blu*_*rni 7 c++ pointers c++11

我需要能够访问(只读,不涉及调整大小或类似的东西)一个std::vectorvia指针的元素.例如,

std::vector<int> foo(10);
int *ptr_begin = &foo[0];
Run Code Online (Sandbox Code Playgroud)

到目前为止一切顺利,这保证在当前标准(23.3.6.1)中有效:

向量的元素是连续存储的,这意味着如果v是一个向量,其中T是某种类型而不是bool,那么它服从所有0 <= n <v的身份&v [n] ==&v [0] + n .尺寸()​​.

因此,我们可以使用指针访问向量的所有元素,因为它们存储在连续的内存块中.但是那个过去最后一个元素呢?我的意思是,执行此操作是合法的吗?

int *ptr_end = ptr_begin + foo.size()
Run Code Online (Sandbox Code Playgroud)

(注意,我不是试图访问过去的最后一个值,只是为了定义一个指向它的指针 - 等同于foo.end()你喜欢的).该标准仅提到通过指针算术访问元素,但显然我们不访问任何元素.

(作为旁注,过去最后一些东西的存在的定义似乎与数组的基本概念紧密相关(参见例如5.7/5),但在整个标准中,它似乎是连续存储的概念和数组可以互换使用.我读错了吗?)

dlf*_*dlf 13

是的,只要您在比较中仅使用ptr_end *并且不尝试遵循它,这很好.引用C++ 11草案标准中的第5.7节关于使用指针的附加操作(强调我的):

如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出; 否则,行为未定义.

在第5.9节中列出了关系运营商的类似规定:

如果两个指针指向同一数组的元素或超出数组末尾的指针,则指向具有较高下标的对象的指针会比较高.

至于vector为了上述目的,缓冲区是否计为数组,§8.3.4规定:

数组类型的对象包含一个类型为T的连续分配的非空N个子对象集.

这与§23.3.6.1必须说的一致vector:

矢量的元素是连续存储的


由于指针是iterators,这种事情是使用标准库算法和任意内存块作为输入的一个方便的技巧.例如,假设您要使用该lower_bound算法,但您的数据存储在MFC CArray中:

CArray<int> someInts;
// populate and check for empty
int* begin = someInts.GetData();
int* end = begin + someInts.GetSize(); // for bounds-checking only; don't dereference
int* answer = std::lower_bound(begin, end, 100);
Run Code Online (Sandbox Code Playgroud)

*还有其他一些合法的操作; 例如,因为你知道你的向量不是空的,你可以减去一个得到指向最后一个元素的指针.重要的是不要取消引用.

  • 您可能希望使用foo.data()而不是&foo [0]来获取指向开头的指针,因为即使对于空向量也能正常工作. (2认同)