C ++向量有额外的空间,但为什么指针仍然指向一个未定义的空间?

时间:2017-06-09 07:47:23

标签: c++

这是我的编码:

vector<int>a;
a.reserve(14);
for (int i = 0; i < 10; i++) a.push_back(i);
a.end()++;

我分配了14个内存,但是我在这个向量中只使用了10个内存,所以我可以使用4个内存,但是当我使尾指针移动一位指向下一个内存时,编译器通知我尾指针指向一个未定义的空间,为什么?有四种记忆未被使用,我不明白。

以下是循环的操作:

                                a.end() --v   v-- a.end()++
 -------------------------------------------------------
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |   |   |   |   |
 -------------------------------------------------------

我只是认为a.end()++指向a.end()之后存在的第12个内存。但为什么我不能制作一个指向那个空间的指针?

2 个答案:

答案 0 :(得分:4)

有两件事需要考虑:

<强> 1 想想end()正在返回的内容:

  

返回一个迭代器,引用向量容器中的past-the-end元素。

     

过去结束元素是跟随向量中最后一个元素的理论元素。它没有指向任何元素,因此不应被解除引用。   所以end()返回一个 not 的元素,它对于在循环条件中检查迭代器很有用:iter != vec.end()

<强> 2 再次误解了STL容器的大小容量

size(get by size())是存储在容器中的实际元素数。不同编译器之间的大小可能不同。在您的示例中,其中包含pushed back 10个元素。

capacity(get by capacity())是您的容器在引擎盖下使用的内存。这意味着在您的示例中,您reserved 14个元素作为容量。您可以将14个元素放入向量中,而无需重新分配。

简而言之:循环后,矢量大小为10,容量为14. end()返回的迭代器指向不存在的11.元素。如果增加,则指向即使不存在的12.元素。当涉及到越界访问时,向量的at()方法得到了很好的解释:

  

该函数自动检查n是否在vector的有效元素范围内,如果不是{(3)}则抛出out_of_range异常(即,如果n大于或等于,则size)。

这意味着您只需访问:0 <= n < size()

还要考虑有一个resize()函数,它调整向量的大小,使其包含给定数量的元素。如果您使用resize()代替reserve(),则必须使用[] operatorat() method,因为如果您push_back()有更多元素,那么它将会落后于reserve()实际大小。

越界访问: 如果你想访问{{3}}在大小之后分配的内存,你可以vec[vec.size() + n] ... // access invalid!实际上你永远不应该这样做!)。如果没有编译器给你一个警告,这是可能的,因为编译器可以检查向量的大小。 程序甚至不会在运行时崩溃,因为向量的内存保证是连续的。所以正如你所说的那样,内存就在大小之后。但是你通常不关心矢量的分配方式以及它背后的大小。 vector类是一个安全的抽象层,位于内存之上。

答案 1 :(得分:2)

我看不到保证在位置size() < position < capacity()访问矢量数据的方法,即使有人认为底层内存是为capacity()个元素保留的。原因是类vector的标准仅在0..size()-1范围内定义/保证访问,并且实现不必须保证访问超出该范围。

以函数T* vector::data()为例,其中......

  

返回指向用作元素存储的基础数组的指针。   指针是范围[data(); data()+ size())总是一个   有效范围,即使容器为空(data()不是   在那种情况下可以解除引用)

即使您获得了指向底层内存结构的指针,该标准也不保证在size() - 位置之后访问。

因此即使像int x = v.data[v.size()]这样的访问(假设仍然在容量范围内)可能不会崩溃,这样的访问依赖于库实现细节,因此肯定不可移植并且可能引入未定义的行为