簡體   English   中英

如果向量有足夠的空間(通過儲備創建),std :: vector :: insert()是否會使迭代器無效?

[英]Does std::vector::insert() invalidate iterators if the vector has enough room (created through reserve)?

回答如何自我復制載體? 使我對迭代器無效感到困惑。 一些文獻說:“如果使用insert,push_back等,則認為所有迭代器均無效”。 顯然,這可能會導致向量增長,從而使迭代器無效。 我知道會有足夠的空間怎么辦?

第一次嘗試:

myvec.reserve(myvec.size()*3);  //does this protect me from iterator invalidation?
vector<string>::iterator it = myvec.end();    
myvec.insert(myvec.end(), myvec.begin(), it);
myvec.insert(myvec.end(), myvec.begin(), it);

經過一些出色的回答后,請再次嘗試:

auto size = myvec.size();
myvec.reserve(size*3);  //does this protect me from iterator invalidation?  
myvec.insert(myvec.end(), myvec.begin(), myvec.begin()+size);
myvec.insert(myvec.end(), myvec.begin(), myvec.begin()+size);

經過更出色的回答后,第三次嘗試:

auto size = myvec.size();
myvec.reserve(size*3);  //does this protect me from iterator invalidation?  
back_insert_iterator< vector<string> > back_it (myvec);
copy (myvec.begin(),myvec.begin()+size,back_it);
copy (myvec.begin(),myvec.begin()+size,back_it);

引用自Josuttis的“ C ++標准庫參考”:

插入或刪除元素會使引用以下元素的引用,指針和迭代器無效。 如果插入導致重新分配,它將使所有引用,迭代器和指針無效。

建議我的代碼安全且行為明確。 標准中是否有段落可以保證這一點?

過去的迭代器總是有點特殊。 我會注意的 該標准說(23.3.6.5):

如果沒有發生重新分配,則插入點之前的所有迭代器和引用均保持有效。

此處的關鍵是“插入點之前”。 因為你原來it不是將插入點之前(因為它插入點),我不會行其上剩余的有效。

盡管確實可以做到,只要不超過容量,插入向量不會引起重新分配,並且不會使插入點之前的元素的迭代器無效(這可以說是end()的情況,正如@KerrekSB指出的那樣) out),C ++ 11標准的表100(第23.2.3段a.insert(p,i,j)為序列容器的a.insert(p,i,j)函數指定了以下前提條件

[...] pre:i和j不是a的迭代器。 [...]

在您的情況下,它們顯然是,這使我認為程序具有未定義的行為。

迭代器不應在功能中間失效。 內存可能會被重新分配的想法不會成立,因為您不能在具有非平凡構造函數的對象上使用realloc 即使構造不是問題,在最壞的情況下,它仍然必須復制兩次初始序列,而在一般情況下,則沒有任何好處。

要點是,以這種方式實現它沒有任何意義; 不管標准怎么說,幾乎都可以確定alloccopyfree

這是安全的,因為v.begin()v.end()始終是最新的。

v.insert(v.end(), v.begin(), v.end());
v.insert(v.end(), v.begin(), v.end());

這不是。

vector<foo>::iterator i = v.begin();
vector<foo>::iterator j = v.end();
v.insert(v.end(), i, j);
v.insert(v.end(), i, j);

但是,自我插入可能會很不穩定。 在GCC下嘗試以下操作。 當有足夠的可用內存時,自我插入才會給出錯誤的結果(不確定這是否是錯誤)。

int main()
{
    int position = 1, first = 2, last = 3;
    // enforce error condition.
    assert(position < first);
    int size = 8;
    // sanity check.
    assert(first < last && last <= size);

    std::vector<int> right, wrong;
    // force resize during insertion.
    right.reserve(size);
    // avoid resize during insertion.
    wrong.reserve(size + (last - first));

    for ( int i = 0; i < size; i++ )
     {
       right.push_back(i);
       wrong.push_back(i);
     }

    std::vector<int>::iterator i;
    i = right.begin();
    right.insert(i + position, i + first, i + last);
    i = wrong.begin();
    wrong.insert(i + position, i + first, i + last);

    assert(right == wrong);
    return 0;
}

注意:以上觀點專門適用於vector ,通常不適用於容器。 同樣,上述行為可能是錯誤的建議與標准無關,而是為vector實現強大的自我插入的簡便性。

暫無
暫無

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

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