C++ access vector beyond size() and under capacity()
在索引i之外和向量capacity()下的索引i中访问向量data()[i]是否安全?
这是我的理由:
a)根据cplusplus,capacity()是"当前为向量分配的存储空间的大小",这使我认为问题的答案是YES,但是
b)使用reserve()并访问vector size()之外的data应该是安全的,因为根据cplusplus的说法,reserve()"导致容器重新分配其存储,从而将其容量增加到n",但是然后
c)Stackoverflow主题与上面的b)语句
相矛盾
所以我很困惑,正在寻找答案。
- 取决于您对安全的定义。程序可能不会崩溃,但是结果是不确定的。
-
它还取决于访问的类型。例如,调用就地构造函数可能是安全的,但调用operator=可能不是安全的。
-
如果您超出了size()的范围,许多调试运行时库将通过assert使程序停止运行。例如,Visual C调试运行时将暂停您的程序。
-
在索引0和size()之间,您具有有效的数据,在索引size()和capacity()之间,您仅具有有效的内存。充其量您可以初始化有效内存,但是矢量仍然无法以任何有意义的方式对其进行管理。这里有一些绕过矢量接口的原因的详细信息:lemire.me/blog/2012/06/20/do-not-waste-time-with-stl-vectors
-
注意:cplusplus.com倾向于对初学者来说易于阅读而不是准确性。除非遇到需要字面正确性的问题,否则这很好。到那时,最好使用cppreference,如果那还不够好,请转到C标准。请注意,当您进入更深入,更正确的文档时,如果没有强大的后盾知识(有时甚至是法律学位),则很难理解。
如果n >= size(),则访问data()[n]无效。每个[vector.data] std::vector::data
Returns: A pointer such that [data(), data() + size()) is a valid range. For a non-empty vector, data() == addressof(front()).
因此,仅使用[0, size())范围内的值访问data是有效的。
通常,data() + size() - 1和data + capacity()之间的内存未初始化。如果您从该未初始化的内存中读取,则为未定义的行为。如果您的对象具有非平凡的初始化,那么您甚至无法为其分配值,因为该位置实际上没有对象,仅一个空间就可以了。您可能会在未初始化的范围内执行操作,但是您违反了std::vector的合同,如果您这样做,可能会很生气;)
- 在size()之后,事情变得很有趣。库的实现可能包括检查越界访问并通过错误消息暂停程序的代码。它什么也做不了,让程序使用未知的数据值。它可以玩马卡雷纳(La Macarena)。
-
该推论是不正确的。该声明没有说其他什么是有效的。 @DavidSchwartz的评论更是重点。
-
非常感谢您提供的链接。这里的vector.capacity不太模糊:The total number of elements that the vector can hold without requiring reallocation。这并不意味着data()返回指向大小为capacity的区域的指针的事实
-
@ user4581301这使我想起有一天要做一个C实现,无论何时调用UB或实现定义的行为允许它,La Macarena都会在它可以找到的每个帧缓冲区中播放Rick Ashleys图片。
不,这是不安全的,因为ISO / IEC 14882:2014的§23.3.6.4规定了
vector data ... Returns: A pointer such that [data(),data() + size()) is a valid range.
因此,按照标准,size()以外的所有内容均未定义,这意味着每个人都会确认的所谓未定义行为是非常不安全的。
说句公道话,通常不会发生任何不好的情况,但这通常是非常弱的,这意味着会发生另一种编译器,操作系统和繁荣时期,您无法分辨。并且为了完整起见,有几种实现可能会崩溃的实现,例如,当您使用地址清理进行编译时,我认为。只是不要这样做。
-
关于每个人都会确认的问题,我记得一个孩子的广告,说过十分之九的牙医都同意刷牙是件好事。我一直想知道那个第十位牙医怎么了。