[英]How does std::vector::end() iterator work in memory?
Today, I was attempting to extract a subset of N elements from a vector of size M, where N < M. I realised that I did not need to create a new copy, only needed to modify the original, and moreover, could take simply the first N elements. 今天,我试图从大小为M的向量中提取N个元素的子集,其中N <M。我意识到我不需要创建新副本,只需要修改原始副本,并且只需简单地前N个元素。
After doing a few brief searches, there were many answers, the most attractive one being resize() which appears to truncate the vector down to length, and deal neatly with the memory issues of erasing the other elements. 经过几次简短的搜索后,有很多答案,其中最吸引人的是resize(),它似乎将向量截短了长度,并巧妙地处理了擦除其他元素的内存问题。
However, before I came across vector.resize(), I was trying to point the vector.end() to the N+1'th position. 但是,在遇到vector.resize()之前,我试图将vector.end()指向第N + 1个位置。 I knew this wouldn't work, but I wanted to try it regardless.
我知道这行不通,但是无论如何我都想尝试一下。 This would leave the other elements past the N'th position "stranded", and I believe (correct me if i'm wrong) this would be an example of a memory leak.
这会使其他元素超出第N个位置“搁浅”,我相信(如果我错了,请纠正我)这将是内存泄漏的一个示例。
On looking at the iterator validity on http://www.cplusplus.com/reference/vector/vector/resize/ , we see that if it shrinks, vector.end() stays the same. 在http://www.cplusplus.com/reference/vector/vector/resize/上查看迭代器的有效性时,我们看到,如果迭代器有效,则vector.end()保持不变。 If it expands, vector.end() will move (albeit irrelevant to our case).
如果扩展,vector.end()将移动(尽管与我们的情况无关)。
This leads me to question, what is the underlying mechanic of vector.end()? 这使我提出疑问, vector.end()的基本机制是什么? Where does it lie in memory?
它在哪里记忆? It can be found incrementing an iterator pointing to the last element in the vector, eg auto iter = &vector.back(), iter++, but in memory, is this what happens?
可以发现增加指向向量中最后一个元素的迭代器,例如auto iter =&vector.back(),iter ++,但是在内存中,这会发生什么吗?
I can believe that at all times, what follows vector.begin() should be the first element, but on resize, it appears that vector.end() can lie elsewhere other than past the last element in the vector. 我可以相信,始终在vector.begin()之后的内容应该是第一个元素,但是在调整大小时,似乎vector.end()可以位于除向量中最后一个元素之外的其他位置。
For some reason, I can't seem to find the answer, but it sounds like a very basic computer science course would contain this information. 出于某种原因,我似乎找不到答案,但这听起来像是一门非常基础的计算机科学课程将包含此信息。 I suppose it is stl specific, as there are probably many implementations of a vector / list that all differ...
我想它是stl特有的,因为vector / list的许多实现可能都不同...
Sorry for the long post about a simple question! 抱歉,关于一个简单问题的冗长帖子!
you asked about "the underlying mechanic of vector.end()". 您问过“ vector.end()的基本机制”。 Well here is (a snippet of) an oversimplified vector that is easy to digest:
好吧,这是一个易于消化的过度简化的向量(摘要):
template <class T>
class Simplified_vector
{
public:
using interator = T*;
using const_interator = const T*;
private:
T* buffer_;
std::size_t size_;
std::size_t capacity_;
public:
auto push_back(const T& val) -> void
{
if (size_ + 1 > capacity_)
{
// buffer increase logic
//
// this usually means allocation a new larger buffer
// followed by coping/moving elements from the old to the new buffer
// deleting the old buffer
// and make `buffer_` point to the new buffer
// (along with modifying `capacity_` to reflect the new buffer size)
//
// strong exception guarantee makes things a bit more complicated,
// but this is the gist of it
}
buffer_[size_] = val;
++size_;
}
auto begin() const -> const_iterator
{
return buffer_;
}
auto begin() -> iterator
{
return buffer_;
}
auto end() const -> const_iterator
{
return buffer_ + size_;
}
auto end() -> iterator
{
return buffer_ + size_;
}
};
Also see this question Can std::vector<T>::iterator simply be T*? 另请参阅此问题std :: vector <T> :: iterator可以简单地设为T *吗? for why
T*
is a perfectly valid iterator
for std::vector<T>
为什么
T*
是std::vector<T>
的完美有效iterator
Now with this implementation in mind let's answer a few of your 现在考虑到此实现,让我们回答一些
misconceptions questions: 误解
问题:
I was trying to point the vector.end() to the N+1'th position.
我试图将vector.end()指向第N + 1个位置。
This is not possible. 这是不可能的。 The end iterator is not something that is stored directly in the class.
最终迭代器不是直接存储在类中的东西。 As you can see it's a computation of the begging of the buffer plus the size (number of elements) of the container.
如您所见,它是对缓冲区的请求加上容器大小(元素数)的计算。 Moreover you cannot directly manipulate it.
而且,您不能直接操纵它。 The internal workings of the class make sure
end()
will return an iterator pointing to 1 past the last element in the buffer. 该类的内部工作方式确保
end()
将返回指向缓冲区最后一个元素之后的1的迭代器。 You cannot change this. 您无法更改。 What you can do is insert/remove elements from the container and the
end()
will reflect these new changes, but you cannot manipulate it directly. 您可以做的是从容器中插入/删除元素,
end()
将反映这些新更改,但是您不能直接对其进行操作。
and I believe (correct me if i'm wrong) this would be an example of a memory leak.
并且我相信(如果我错了,请纠正我)这将是内存泄漏的一个示例。
you are wrong. 你错了。 Even if you somehow make
end
point to something else that what is supposed to point, that wouldn't be a memory leak. 即使您以某种方式将
end
指向应该指向的其他地方,也不会造成内存泄漏。 A memory leak would be if you would lost any reference to the dynamically allocated internal buffer. 如果您丢失对动态分配的内部缓冲区的任何引用,就会发生内存泄漏。
The "end" of any contiguous container (like a vector or an array) is always one element beyond the last element of the container. 任何连续容器(例如向量或数组)的“结束”始终是容器最后一个元素之外的一个元素。
So for an array (or vector) of X elements the "end" is index X (remember that since indexes are zero-based the last index is X - 1). 因此,对于X个元素的数组(或向量),“结束”是索引X(请记住,由于索引是从零开始的,所以最后一个索引是X-1)。
This is very well illustrated in eg this vector::end
reference . 例如, 在
vector::end
reference中对此进行了很好的说明。
If you shrink your vector, the last index will of course also change, meaning that the "end" will change as well. 如果缩小向量,则最后一个索引当然也会更改,这意味着“ end”也将更改。 If the end-iterator does not change, then it means you have saved it from before you shrank the vector, which will change the size and invalidate all iterators beyond the last element in the vector, including the end iterator.
如果最终迭代器没有更改,则意味着您在收缩向量之前已保存了该迭代器,这将更改大小, 并使除向量中最后一个元素之外的所有迭代器(包括最终迭代器) 无效 。
If you change the size of a vector, by adding new elements or by removing elements, then you must re-fetch the end iterator. 如果通过添加新元素或删除元素来更改向量的大小,则必须重新获取结束迭代器。 The existing iterator objects you have will not automatically be updated.
您拥有的现有迭代器对象将不会自动更新。
Usually the end isn't stored in an implementation of vector. 通常,结尾不存储在vector的实现中。 A vector stores:
向量存储:
When you call end() this returns begin() + size(). 当您调用end()时,将返回begin()+ size()。 So yes, end() is a pointer that points to one beyond the last element.
因此,是的,end()是一个指向最后一个元素之外的指针。
So the end() isn't a thing that you can move. 因此,end()不能移动。 You can only change it by adding or removing elements.
您只能通过添加或删除元素来更改它。
If you want to extract a number of elements 'N' you can do so by reading those from begin() to begin() + 'N'. 如果要提取多个元素“ N”,则可以通过读取从begin()到begin()+'N'的元素来提取。
for( var it = vec.begin(); it != begin() + n; ++it )
{
// do something with the element (*it) here.
}
Many stl algorithms take a pair of iterators for the begin and end of a range of elements you want to work with. 许多stl算法在要使用的一系列元素的开始和结束处都带有一对迭代器。 In your case, you can use vec.begin() and vec.begin() + n as the begin and end of the range you're interested in.
对于您的情况,可以将vec.begin()和vec.begin()+ n用作您感兴趣的范围的开始和结束。
If you want to throw away the elements after n, you can do vec.resize(n). 如果要丢弃n之后的元素,可以执行vec.resize(n)。 Then the vector will destruct elements you don't need.
然后,向量将破坏您不需要的元素。 It might not change the size of the memory block the vector manages, the vector might keep the memory around in case you add more elements again.
它可能不会更改向量管理的内存块的大小,如果再次添加更多元素,向量可能会保留内存。 That's an implementation detail of the vector class you're using.
这是您使用的向量类的实现细节。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.