[英]Accessing std::vector elements via pointers vs end()
我需要能够通过指针访问(只读,不涉及调整大小或类似的东西) std::vector
的元素。 例如,
std::vector<int> foo(10);
int *ptr_begin = &foo[0];
到目前为止一切顺利,这保证在当前标准(23.3.6.1)中有效:
向量的元素是连续存储的,这意味着如果v是一个向量,其中T是某种类型而不是bool,那么它服从所有0 <= n <v的身份&v [n] ==&v [0] + n 。尺寸()。
因此,我们可以使用指针访问向量的所有元素,因为它们存储在连续的内存块中。 但是那个过去最后一个元素呢? 我的意思是,执行此操作是合法的吗?
int *ptr_end = ptr_begin + foo.size()
(注意,我不是试图访问过去的最后一个值,只是为了定义一个指向它的指针 - 如果你愿意的话,相当于foo.end()
)。 该标准仅提到通过指针算术访问元素,但显然我们不访问任何元素。
(作为旁注,过去最后一些东西的存在的定义似乎与数组的基本概念紧密相关(参见例如5.7 / 5),但在整个标准中,它似乎是连续存储的概念和数组可以互换使用。我读错了吗?)
是的,只要您在比较中仅使用ptr_end *并且不尝试遵循它,这很好。 引用C ++ 11草案标准中的第5.7节关于使用指针的附加操作(强调我的):
如果指针操作数和结果都指向同一个数组对象的元素, 或者指向数组对象的最后一个元素 ,则评估不应产生溢出; 否则,行为未定义。
在第5.9节中列出了关系运营商的类似规定:
如果两个指针指向同一数组的元素或超出数组末尾的指针,则指向具有较高下标的对象的指针会比较高。
至于vector
的缓冲区是否算作上述目的的数组,§8.3.4规定:
数组类型的对象包含一个类型为T的连续分配的非空N个子对象集。
这与§23.3.6.1对vector
说法是一致的:
矢量的元素是连续存储的
由于指针是iterator
,因此使用标准库算法以及任意内存块作为输入时,这种方法就是一种方便的技巧。 例如,假设您要使用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);
*还有其他一些合法的操作; 例如,因为你知道你的向量不是空的,你可以减去一个得到指向最后一个元素的指针。 重要的是不要取消引用。
你应该记住std::vector::data()
,它明确地给你指向这个连续内存的指针。 所以是的,只读操作是可用的(如果你没有将它们与其他矢量方法混合,可以在下面进行一些重新分配等)。
我甚至会更进一步 - 改变std::vector::data()
下的内存内容也应该是合法的。
是的,将结果形成一个过去的元素是合法的。 尊重它是不合法的。 标准草案甚至还有一个脚注,其中指出“实现只需要在对象结束后提供一个额外的字节(可能与程序中的另一个对象重叠),以满足”超过最后一个元素“的要求” 。 您也可以使用它进行指针数学运算(至少在处理指向数组的指针时可以执行的所有法律操作)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.