如果向量有足够的空间(通过保留创建),std::vector::insert()是否会使迭代器无效



回答如何自复制矢量?让我对迭代器无效有点困惑。有些文献说"如果使用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不在插入点之前(因为它插入点),我不会指望它保持有效。

尽管确实,只要不超过容量,插入到向量中就不会导致重新分配,并且不会使插入点之前元素的迭代器无效(正如@KerrekSB所指出的,end()就是这样),C++11标准的表100(第23.2.3段)规定了序列容器的a.insert(p,i,j)函数的以下先决条件

〔…〕pre:i和j不是a的迭代器。〔…〕

在你的情况下,它们显然是,这让我认为这个程序有未定义的行为。

Iterator不应在函数中间无效。内存可能被重新定位的想法是站不住脚的,因为不能在具有非平凡构造函数的对象上使用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,而非一般容器。此外,上述行为可能是一个bug的说法与标准无关,而是与实现vector的健壮自插入的容易性无关。

相关内容

最新更新