繁体   English   中英

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM