回答How to self-copy a vector?让我对迭代器失效感到有些困惑。一些文献说"如果你使用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的引述&#39; &#34; C ++标准库参考&#34;:
插入或移除元素 使引用,指针和 引用以下内容的迭代器 元件。如果插入导致 重新分配,它使所有人失效 引用,迭代器和指针。
表明我的代码是安全且定义的行为。标准中是否有一个保证这一点的段落?
答案 0 :(得分:6)
过去的迭代器总是有点特别。我小心点标准说明了这一点(23.3.6.5):
如果没有重新分配,插入点之前的所有迭代器和引用仍然有效。
这里的关键是“插入点之前”。由于您的原始it
不在插入点之前(因为 是插入点),因此我不会将其保留为有效。
答案 1 :(得分:2)
虽然只要不超出容量,插入到向量中就不会导致重新分配,并且在插入点之前不会使元素的迭代器无效(可以说是end()
的情况,如@KerrekSB指出的那样),C ++ 11标准的表100(第23.2.3段)为a.insert(p,i,j)
函数指定了以下前提条件序列容器:
[...] pre:i和j不是迭代器。 [...]
在你的情况下,他们显然是,这让我觉得程序有未定义的行为。
答案 2 :(得分:0)
迭代器不应该在函数中失效。内存可能重定位的想法并不成立,因为你不能在具有非平凡构造函数的对象上使用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
,而不适用于一般的容器。此外,上述行为可能是错误的建议与标准无关,而是为vector
实现强大的自我插入的简易性。