我需要能够通过指针访问{只读,不涉及大小调整或类似的东西)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),但在整个标准中它似乎是概念连续存储和数组可以互换使用。我读错了吗?)
答案 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)
是的,将地址形成为一个过去的元素是合法的。尊重它是不合法的。标准草案甚至有一个脚注,它注意到“实现只需要在对象结束后提供一个额外的字节(可能与程序中的另一个对象重叠),以满足”一个过去的最后一个元素“要求” 。您也可以使用它进行指针数学运算(至少在处理指向数组的指针时可以执行的所有法律事务)。