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

时间:2014-05-13 15:20:49

标签: c++ pointers c++11

我需要能够通过指针访问{只读,不涉及大小调整或类似的东西)std::vector的元素。如,

std::vector<int> foo(10);
int *ptr_begin = &foo[0];

到目前为止一切顺利,这保证可以在当前标准(23.3.6.1)中使用:

  

向量的元素是连续存储的,这意味着如果v是一个向量,其中T是除bool之外的某种类型,那么它服从身份&amp; v [n] ==&amp; v [0] + n全0&lt; = n&lt; v.size()。

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

int *ptr_end = ptr_begin + foo.size()

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

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

3 个答案:

答案 0 :(得分:13)

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

  

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

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

  

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

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

  

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

这与§23.3.6.1关于vector

的说法是一致的
  

矢量的元素是连续存储的


由于指针是iterator s,因此使用标准库算法和任意内存块作为输入时,这种方法很方便。例如,假设您要使用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);

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

答案 1 :(得分:1)

你应该记住std::vector::data()的存在,它明确地给你指向这个连续记忆的指针。所以是的,只读操作是可用的(如果你没有将它们与其他矢量方法混合,可以在下面进行一些重新分配等。)

我甚至会更进一步 - 改变std::vector::data()下的内存内容也应该是合法的。

答案 2 :(得分:1)

是的,将地址形成为一个过去的元素是合法的。尊重它是不合法的。标准草案甚至有一个脚注,它注意到“实现只需要在对象结束后提供一个额外的字节(可能与程序中的另一个对象重叠),以满足”一个过去的最后一个元素“要求” 。您也可以使用它进行指针数学运算(至少在处理指向数组的指针时可以执行的所有法律事务)。