簡體   English   中英

iterator和back_insert_iterator有什么區別?

[英]What's the difference between iterator and back_insert_iterator?

如果隨機訪問迭代器可以用於訪問相對於它們指向的元素的任意偏移位置的元素(不知何故像指針),為什么不能在std::copy()等通用算法中使用它們而不是使用back_insert_iterator ,兩者之間有什么區別?

std::back_insert_iterator是一種特定輸出迭代器,它支持push_back操作。 當您使用operator= 寫入它時,它會將值push_backs到底層容器中 - 因此,從這個意義上說,它充當具有push_back成員函數的容器的適配器。

一個例子很容易理解:

std::vector<int> v;

std::back_insert_iterator<std::vector<int>>  it(v);

*it = 10; // it is equivalent to v.push_back(10);
 it = 99; // it is ALSO equivalent to v.push_back(99);

for (auto const & i : v)
    std::cout << i << " " ; //10 99

它輸出:

10 99

在線演示

通常的迭代器操作++* it沒有影響。

但是你很少直接使用它們(我從未直接使用它直到現在)。 您可以將它們與算法一起使用,例如std::copy在這種情況下,您還可以使用std::back_inserter 函數返回std::back_insert_iterator類型的對象。

//assuming dest is a container which supports push_back!
std::copy(src.begin(), src.end(), std::back_inserter(dest));

您還希望看到以下(適配器)迭代器:

因此,根據容器,您選擇適配器迭代器。

請注意,它們都是輸出迭代器。

為什么不能在std :: copy()等通用算法中使用它們而不是使用back_insert_iterator。

當然,您可以在std::copy等算法中使用隨機訪問迭代器(或任何輸出迭代器)作為第三個參數,但是假設迭代器引用現有范圍 - *it++it是明確定義的你傳遞的價值。 您傳遞它們以覆蓋范圍的現有元素,而std::back_insert_iterator 新元素添加到容器中。

希望有所幫助。

實際上,你可以在std::copy完全使用常規迭代器。

int main() {
    std::vector<int> vec{1, 2, 3, 4};

    std::list<int> list{vec.size()};

    std::copy(vec.begin(), vec.end(), list.begin());

    // list = 1, 2, 3, 4
}

但是,正如您可能注意到的,這意味着:

  • 首先創建len(source range)默認元素
  • 然后將元素從源范圍復制到目標范圍1 x

這是非常低效的,並且要求元素可以默認構造然后分配給。

相反, back_insert_iterator是一個迭代器,它作為普通容器上的適配器運行。 如果你看一下界面,你會發現它根本不像常規迭代器那樣,只要你試圖推送一個項目,就會在它嵌入的底層容器引用上調用push_back

int main() {
    std::list<int> list;

    std::back_insert_iterator<std::list<int>> bii(list);

    bii = 1;
    bii = 2;
    bii = 3;
    bii = 4;

    // list = 1, 2, 3, 4

    // note: decltype(*bii) == bii&, so deferencing bii serves no purpose;
    // similarly, ++bi does nothing either; both operations are just defined
    // to mimick a regular operator interface so it can be used in regular
    // algorithms over iterators.
}

因此,這兩種方法同樣有效,但具有不同的行為:

  • 常規迭代器允許您覆蓋現有范圍
  • back_insert_iterator允許您追加到現有容器

語義是不同的,選擇對手頭的任務有意義。

常規迭代器對它們正在使用的容器一無所知,除了它所持有的數據類型。 為了向容器添加元素,讓我們說一個向量,需要知道向量中的元素數量。

它們可以,但這樣做可能不安全。

我建議閱讀赫爾辛基大學對迭代器的精彩介紹

如果你有一個容器的迭代器(正向,雙向和隨機訪問都很好),並且你在STL算法上下文中使用它作為輸出迭代器,輸出將被寫入容器, 迭代器永遠不會被比較容器的end() 如果所有寫入的元素都適合,那么這很好,但如果沒有,輸出迭代器將到達end() ,並且取消引用它來寫下一個元素將給出未定義的行為。

back_insert_iterator這樣的東西專門用作輸出迭代器,並且不會以這種方式導致UB,因為它們總是可以插入更多元素。

常規迭代器不會更改序列的大小或結構。 特別是隨機訪問迭代器只訪問特定位置的元素。

std::back_insert_iterator<Cont>是一個trmplate,它建模一個具體的輸出迭代器,改變它所引用的每個元素所引用的序列:它為每個寫入的元素調用cont.push_back() 由於迭代器不會讀取它正在修改的序列,因此添加元素的效果非常好。

暫無
暫無

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

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