如何解决使用迭代器时在 STL 中删除和添加元素
我对正在阅读的书中的一段内容感到困惑。
我不明白为什么这本书证明对 STL 使用移除和添加操作是合理的,即使它会导致迭代器无效。有人可以向我澄清这本书试图传达的信息吗?
解决方法
作者试图说明的一点是,虽然 vector::insert
和 vector::erase
可能会使先前创建的迭代器无效,但它们返回的迭代器必然有效,因此您可以依赖它们。
检查此表以准确了解每个 STL 容器何时发生 iter/ref 失效:https://en.cppreference.com/w/cpp/container
,即使这些操作使(一些)旧的、预先存在的迭代器失效,但这并不能阻止新创建的迭代器有效。示例程序将无效迭代器的值分配给(文本中使用的单词中的“重置”)一个有效值。
这是一个不同但类似的例子:
int* ptr; // an iterator
{
int i;
ptr = &i; // ptr is now valid
} // ptr has become invalid because storage duration of i ended
int j;
ptr = &j; // ptr is valid again despite having been invalid earlier
,
在示例中,insert
和 erase
的返回值分配给了 iter
。这两种方法都会使容器中的现有迭代器无效,但它们返回的迭代器是有效的。
对于至少从 C++ 14 标准开始的初学者,您可以在成员函数 const_iterator
和 erase
中使用常量迭代器 insert
。
现在相应的成员函数(在您的代码片段中使用)声明如下
iterator insert(const_iterator position,const T& x);
iterator erase(const_iterator position);
所以你可以写
auto iter = vi.cbegin();
代替
auto iter = vi.begin();
并在 erase
和 insert
的调用中使用它。
使用成员函数 insert
将新元素添加到向量后,向量可以在内部为其元素重新分配内存。在这种情况下,当前迭代器可能无效,因为它会在重新分配之前指向内存。
但该函数返回一个迭代器,该迭代器指向存储在已重新分配的内存中的新插入元素。因此返回的迭代器将指向内存的实际范围。
考虑以下演示程序。
#include <iostream>
#include <vector>
#include <iterator>
int main()
{
std::vector<int> v;
v.insert( v.cbegin(),0 );
std::cout << "v.data() = " << v.data()
<< ",&v[0] = " << &v[0] << '\n';
v.insert( v.cbegin(),1 );
std::cout << "v.data() = " << v.data()
<< ",&v[0] = " << &v[0]
<< ",&v[1] = " << &v[1] << '\n';
return 0;
}
它的输出可能看起来像
v.data() = 0x556699d79e70,&v[0] = 0x556699d79e70
v.data() = 0x556699d7aea0,&v[0] = 0x556699d7aea0,&v[1] = 0x556699d7aea4
如您所见,在插入第二个值后,向量在内部重新分配了存储元素的内存。即在插入第二个值之前,函数 cbegin
返回的当前迭代器指向地址为 0x556699d79e70
的内存范围。插入第二个值后,函数 cbegin
返回的当前迭代器将指向地址为 0x556699d7aea0
的内存范围。即之前的当前迭代器失效。
但是如果你按照下面的方式重写程序。
#include <iostream>
#include <vector>
#include <iterator>
int main()
{
std::vector<int> v;
auto iter = v.cbegin();
iter = v.insert( iter,0 );
std::cout << "v.data() = " << v.data()
<< ",&*iter = " << &*iter << '\n';
iter = v.insert( iter,&*iter = " << &*iter << '\n';
return 0;
}
然后从程序输出中看到
v.data() = 0x55d8c5698e70,&*iter = 0x55d8c5698e70
v.data() = 0x55d8c5699ea0,&*iter = 0x55d8c5699ea0
迭代器 iter
始终指向有效的内存范围,因为它被函数 insert 返回的迭代器重新分配,结果指向有效的内存范围。
同样适用于成员函数erase
。函数迭代器返回的无效。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。