回答如何自复制矢量?让我对迭代器无效有点困惑。有些文献说"如果使用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
。即使施工不是一个问题,在最坏的情况下,它仍然必须复制初始序列两次,在平均情况下否定任何好处。
重点是,以这种方式实施它是没有意义的;alloc
、copy
、free
几乎可以肯定地完成了,而不管标准怎么说。
这是安全的,因为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
的健壮自插入的容易性无关。