C++转C#迭代器适配问题:集合修改后代码行为一致性咨询
注:原始代码中存在笔误,C++部分的
*it、C#索引遍历部分的myList[it]均应为对应迭代器/索引变量iter,回答已默认修正该问题。
1 C++ std::list 迭代器行为说明
- std::list 是双向链表实现,
push_back操作仅新增尾部节点,不会导致任何已有迭代器失效 pop_front操作仅删除头部节点,仅会使指向被删除头部节点的迭代器失效,其余所有迭代器仍保持有效,且指向的元素和之前完全一致- 你给出的原始C++代码中,在执行
push_back、pop_front前已经执行了iter++,此时iter不再指向头部节点,因此这两个操作不会影响iter的有效性,逻辑是成立的。
2 你当前的C#索引遍历代码存在逻辑问题,和原C++行为不一致
C#的List<T>是动态数组实现,和C++的std::list底层逻辑完全不同:
- 执行
RemoveAt(0)时,数组中所有后续元素都会整体向前移动一位,所有元素的索引值都会减1 - 你当前代码中已经先执行了
iter++,再执行RemoveAt(0),相当于下一轮循环的iter指向的位置比原逻辑多偏移了1位,会跳过1个元素,和原C++逻辑不符 - 不需要额外执行
iter++,反而需要修正索引偏移的问题。
3 正确的转换方案
方案A:使用C#的LinkedList<T>实现,和原C++逻辑完全对齐
LinkedList<T>是C#提供的双向链表,行为和C++std::list一致,转换后代码如下:
// LinkedList<int> myList; LinkedListNode<int> iter = myList.First; while (iter != null && !end) { int element = iter.Value; // ... do something iter = iter.Next; // 对应原C++的iter++ if (!end) { myList.AddLast(element); // 对应push_back myList.RemoveFirst(); // 对应pop_front } }
该方案不需要处理索引偏移,行为和原C++代码100%一致。
方案B:如果必须使用List<T>,修正索引逻辑
如果受限于场景只能用List<T>,需要抵消RemoveAt(0)带来的索引偏移:
// List<int> myList; for (int iter = 0; iter < myList.Count && !end; ) { int element = myList[iter]; // ... do something iter++; if (!end) { myList.Add(element); myList.RemoveAt(0); iter--; // 抵消RemoveAt(0)带来的整体索引偏移 } }
注意:该方案RemoveAt(0)的时间复杂度是O(n),列表元素多的时候性能远低于LinkedList<T>方案。
内容的提问来源于stack exchange,提问作者CSharper
相关产品推荐
相关产品推荐

