簡體   English   中英

std :: vector :: end()迭代器如何在內存中工作?

[英]How does std::vector::end() iterator work in memory?

今天,我試圖從大小為M的向量中提取N個元素的子集,其中N <M。我意識到我不需要創建新副本,只需要修改原始副本,並且只需簡單地前N個元素。

經過幾次簡短的搜索后,有很多答案,其中最吸引人的是resize(),它似乎將向量截短了長度,並巧妙地處理了擦除其他元素的內存問題。

但是,在遇到vector.resize()之前,我試圖將vector.end()指向第N + 1個位置。 我知道這行不通,但是無論如何我都想嘗試一下。 這會使其他元素超出第N個位置“擱淺”,我相信(如果我錯了,請糾正我)這將是內存泄漏的一個示例。

http://www.cplusplus.com/reference/vector/vector/resize/查看迭代器的有效性時,我們看到,如果迭代器有效,則vector.end()保持不變。 如果擴展,vector.end()將移動(盡管與我們的情況無關)。

這使我提出疑問, vector.end()的基本機制是什么? 它在哪里記憶? 可以發現增加指向向量中最后一個元素的迭代器,例如auto iter =&vector.back(),iter ++,但是在內存中,這會發生什么嗎?

我可以相信,始終在vector.begin()之后的內容應該是第一個元素,但是在調整大小時,似乎vector.end()可以位於除向量中最后一個元素之外的其他位置。

出於某種原因,我似乎找不到答案,但這聽起來像是一門非常基礎的計算機科學課程將包含此信息。 我想它是stl特有的,因為vector / list的許多實現可能都不同...

抱歉,關於一個簡單問題的冗長帖子!

您問過“ vector.end()的基本機制”。 好吧,這是一個易於消化的過度簡化的向量(摘要):

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_;
   }
};

另請參閱此問題std :: vector <T> :: iterator可以簡單地設為T *嗎? 為什么T*std::vector<T>的完美有效iterator


現在考慮到此實現,讓我們回答一些 誤解 問題:

我試圖將vector.end()指向第N + 1個位置。

這是不可能的。 最終迭代器不是直接存儲在類中的東西。 如您所見,它是對緩沖區的請求加上容器大小(元素數)的計算。 而且,您不能直接操縱它。 該類的內部工作方式確保end()將返回指向緩沖區最后一個元素之后的1的迭代器。 您無法更改。 您可以做的是從容器中插入/刪除元素, end()將反映這些新更改,但是您不能直接對其進行操作。

並且我相信(如果我錯了,請糾正我)這將是內存泄漏的一個示例。

你錯了。 即使您以某種方式將end指向應該指向的其他地方,也不會造成內存泄漏。 如果您丟失對動態分配的內部緩沖區的任何引用,就會發生內存泄漏。

任何連續容器(例如向量或數組)的“結束”始終是容器最后一個元素之外的一個元素。

因此,對於X個元素的數組(或向量),“結束”是索引X(請記住,由於索引是從零開始的,所以最后一個索引是X-1)。

例如, vector::end reference中對此進行了很好的說明。

如果縮小向量,則最后一個索引當然也會更改,這意味着“ end”也將更改。 如果最終迭代器沒有更改,則意味着您在收縮向量之前已保存了該迭代器,這將更改大小, 並使除向量中最后一個元素之外的所有迭代器(包括最終迭代器) 無效

如果通過添加新元素或刪除元素來更改向量的大小,則必須重新獲取結束迭代器。 您擁有的現有迭代器對象將不會自動更新。

通常,結尾不存儲在vector的實現中。 向量存儲:

  1. 指向第一個元素的指針。 如果調用begin(),這就是您要返回的內容。
  2. 已管理的內存塊的大小。 如果調用capacity(),則會獲取可以容納在此分配內存中的元素數。
  3. 正在使用的元素數。 這些是已構造的元素,位於內存塊的第一部分。 其余的內存未使用,但可用於新元素。 如果整個容量已滿,則要添加更多元素,向量將分配一個更大的內存塊並將所有元素復制到該內存塊中,並取消分配原始塊。

當您調用end()時,將返回begin()+ size()。 因此,是的,end()是一個指向最后一個元素之外的指針。

因此,end()不能移動。 您只能通過添加或刪除元素來更改它。

如果要提取多個元素“ N”,則可以通過讀取從begin()到begin()+'N'的元素來提取。

for( var it = vec.begin(); it != begin() + n; ++it )
{
    // do something with the element (*it) here.
}

許多stl算法在要使用的一系列元素的開始和結束處都帶有一對迭代器。 對於您的情況,可以將vec.begin()和vec.begin()+ n用作您感興趣的范圍的開始和結束。

如果要丟棄n之后的元素,可以執行vec.resize(n)。 然后,向量將破壞您不需要的元素。 它可能不會更改向量管理的內存塊的大小,如果再次添加更多元素,向量可能會保留內存。 這是您使用的向量類的實現細節。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM