我很好奇这种事情是否合法:
std::vector<some_class_type> vec;
vec.reserve(10);
some_class_type* ptr = vec.data() + 3; // that object doesn't exist yet
请注意,我没有尝试访问指向的值。
这是标准对data()
所说的内容,但我不确定它是否相关:
返回:指针使
[data(),data() + size())
有效 范围。对于非空向量data() == &front()
。
答案 0 :(得分:3)
您提供的示例未显示任何立即未定义的行为。根据标准,因为您保留的元素数量大于向量的当前容量,将重新分配。由于分配发生在调用reserve
的位置,data()
返回的指针本身有效。
23.3.6.3/2(强调我的)
效果:一种指令,通知向量计划的大小更改,以便它可以相应地管理存储分配。在reserve()之后,如果重新分配,capacity()大于或等于reserve的参数;并且等于capacity()的先前值。 当且仅当当前容量小于reserve()的参数时,才会发生重新分配。如果除了非CopyInsertable类型的move构造函数之外抛出异常,则没有效果。
但是,如果在添加指针位于data() + size()
之外的足够元素之前尝试取消引用指针,或者如果添加的时间超过capacity()
,则会发生未定义的行为。
答案 1 :(得分:1)
data
必须返回一个指向有效范围 ([vector.data]) 的指针。指向该范围的指针,包括指向该范围最后一个元素的指针,在下一次重新分配之前必须保持稳定。当 size()
为零时,data()
指向空范围的末尾,这是一个完全有效的要保留的指针(但当然不能取消引用)。data
必须在接下来的 10 次插入中保持稳定,因此我们可以假设获得了一个大小和对齐合适的存储区域,用于在其中放置 10 个元素的数组,并且 data
指向那个地区的开始。也就是说,实现必须调用一个分配函数并将内部数据指针设置为它的返回值。 (标准中没有直接指示这一定是真的,但我无法想象它可能是假的情况。我假设标准要求的重新分配 ([vector.capacity]) 实际上调用了一个分配函数,例如作为 ::operator new
或 std::malloc
,否则称此操作为“重新分配”将相当可疑。无论如何,似乎无法避免在任何当前架构上进行此类分配)。答案 2 :(得分:0)
在STL的大多数实现中,空向量的reserve
将触发重新分配并确保您指向的数据被拥有/管理。
调整向量大小时,数据的位置(data()
返回的指针的值)可能会发生变化。持有一个指针本身当然是合法的,取消引用它以进行读取,而未初始化当然是未定义的,如果你能保证,在初始化后取消它只是 合法你的矢量没有调整大小,因此你分配的范围仍然在同一个地方。
增加指向malloc
&#39; d的数据的指针很好。在此示例中,您执行指针运算以保存指向您知道已由std::vector
分配的数据的指针。无论指针指向的元素是否曾被初始化,调整大小操作都会出现问题,因为它可能会释放您指向的内存。
答案 3 :(得分:-1)
绝对否:您的指针不能被认为是有效的。在这里证明它是UB:
标准说明了reserve()
具有以下效果的capactity(23.3.6.3):
指示通知计划更改大小的向量,因此 它可以相应地管理存储分配。后 reserve(),capacity()大于或等于reserve的参数 如果重新分配;并且等于容量的先前值() 除此以外。此时重新分配发生,当且仅当 当前容量小于reserve()的参数。
因此,该标准保证如果分配了某些东西且容量不足,则必须在此时进行重新分配。但仅此而已。
这个措辞让实现以其他方式管理空向量。例如,可以完全想象一个实现可能不会为刚刚创建的空向量分配内存,并且仅在添加第一个元素时分配所需的容量(“延迟分配”策略)。
在这种情况下,您的示例将导致指向无效地址的指针。
重要编辑: 有些人可能认为“ if if only only if ”子句将确保必须在示例中进行分配,因为新容量将大于初始容量。但是,该标准 没有对矢量 的初始容量做出任何声明。使用面向集团的懒惰分配策略的实现(即通过最小的集合管理容量,比如10个项目)将符合标准并导致您的示例指向无效地址,如上所述。
答案 4 :(得分:-2)
当然,这是合法的。
您提到的引用无关紧要,因为 size
不等于 reserve
提供的“保留空间”。
您也可以在 vec.data()+3
之前初始化 vec[0]
,但不会更新向量的“大小”变量。
因此,尽管使用 vector 非常不受欢迎,但 vector 只不过是动态分配数组的一个瘦包装器,以这种方式滥用 vector 并不违法。
经验法则:一旦您使用 vector::data()
函数,您就做错了事。