![](/img/trans.png)
[英]std::map with iterators to std::list from iterators of std::map
[英]Keeping std::list iterators valid through insertion
注意:这不是我应该“使用列表还是双端队列”的问题。 面对insert()
,这是一个关于迭代器有效性的问题。
这可能是一个简单的问题,我太密集了,看不到正确的方法。 我正在实现(无论好坏)网络流量缓冲区作为std::list<char> buf
,并且我将当前读取的 position 维护为迭代器readpos
。
当我添加数据时,我会做类似的事情
buf.insert(buf.end(), newdata.begin(), newdata.end());
我现在的问题是,如何保持readpos
迭代器有效? 如果它指向旧buf
的中间,那么它应该没问题(通过 std::list 的迭代器保证),但通常我可能已经读取并处理了所有数据并且我有readpos == buf.end()
。 插入后,我希望readpos
始终指向下一个未读字符,在插入的情况下应该是第一个插入的字符。
有什么建议么? (没有将缓冲区更改为std::deque<char>
,这似乎更适合该任务,如下所示。)
更新:通过 GCC4.4 的快速测试,我观察到 deque 和 list 在readpos = buf.end()
方面的行为不同:在最后插入后, readpos 在列表中被破坏,但指向 a 中的下一个元素双端队列。 这是标准保证吗?
(根据cplusplus ,任何 deque::insert() 都使所有迭代器无效。这不好。也许使用计数器比迭代器更好地跟踪双端队列中的 position?)
if (readpos == buf.begin())
{
buf.insert(buf.end(), newdata.begin(), newdata.end());
readpos = buf.begin();
}
else
{
--readpos;
buf.insert(buf.end(), newdata.begin(), newdata.end());
++readpos;
}
不优雅,但它应该工作。
来自http://www.sgi.com/tech/stl/List.html
“列表具有重要的属性,即插入和拼接不会使列表元素的迭代器无效,即使删除也只会使指向被删除元素的迭代器无效。”
因此, readpos
在插入后应该仍然有效。
然而...
std::list< char >
是解决此问题的一种非常低效的方法。 您存储在std::list
中的每个字节都需要一个指针来跟踪字节,加上列表节点结构的大小,通常还有两个指针。 也就是说,至少有 12 或 24 个字节(32 或 64 位)的 memory 用于跟踪单个数据字节。
std::deque< char>
可能是一个更好的容器。 像std::vector
一样,它在后面提供恒定时间插入,但它也在前面提供恒定时间删除。 最后,像std::vector
std::deque
是一个随机访问容器,因此您可以使用偏移量/索引而不是迭代器。 这三个特点使它成为一个有效的选择。
我确实很密集。 该标准为我们提供了我们需要的所有工具。 具体来说,序列容器要求 23.2.3/9 说:
从
a.insert(p, i, j)
返回的迭代器指向插入到a
中的第一个元素的副本,如果i == j
则指向p
。
接下来, list::insert
的描述说 (23.3.5.4/1):
不影响迭代器和引用的有效性。
所以事实上,如果pos
是我当前正在使用的列表中的迭代器,我可以说:
auto it = buf.insert(buf.end(), newdata.begin(), newdata.end());
if (pos == buf.end()) { pos = it; }
我的列表中新元素的范围是[it, buf.end())
,尚未处理的元素的范围是[pos, buf.end())
。 这是因为如果pos
在插入之前等于buf.end()
,那么它仍然在插入之后,因为插入不会使任何迭代器失效,甚至不会使结尾失效。
list<char>
是一种非常低效的存储字符串的方法。 它可能比字符串本身大 10-20 倍,而且您正在为每个字符追逐一个指针......
您是否考虑过使用std::dequeue<char>
代替?
[编辑]
要回答您的实际问题,添加和删除元素不会使list
中的迭代器无效......但是end()
仍然是end()
。 因此,您需要在插入新元素以更新您的readpos
迭代器时将其作为特殊情况进行检查。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.