我目前的家庭作业让我为列表创建一个迭代器类。我坚持创造一个好的erase(iterator where)
功能。
当前代码(简化为适合问题):
class List
{
class _Iter
{
friend class List;
public:
_Iter(ListElem *pCurr, List *pList);
/* *, ->, ++, --, == and != operators overloaded */
private:
ListElem *pCurr_; List *pList_;
};
typedef _Iter iterator;
iterator erase(iterator where);
};
执行擦除操作如下:
// Precondition: List has been checked for size > 0.
List::iterator List::erase(List::iterator& where)
{
// Erasing only element in list.
if(where == end() && where == begin())
{
pop_back(); // or pop_front();
return iterator(0, this);
}
// Elem at end
if(where == end())
{
pop_back();
return end();
}
else
{
// Elem at beginning
if(where == begin())
{
pop_front();
return ++begin();
}
}
// Elem somewhere between beginning and end.
iterator temp(where);
// The node next to pCurr_ should point to the one before pCurr_
where.pCurr_->next->prev = where.pCurr_->prev;
// The node before pCurr_ should point to the one after pCurr_
where.pCurr_->prev->next = where.pCurr_->next;
// Return the node after pCurr_
++temp;
delete where.pCurr_;
--size_;
return temp;
}
前三个案例 - 仅元素,结尾元素和开头元素 - 都可以。编码很好,绝对不需要_Iter
成员的知识和私人访问权限。但是,如果元素不在那些位置,那么我(似乎)别无选择,只能违反封装并直接更改pCurr_(列表元素)。
有什么方法可以避免这种情况吗?我查看了STL列表,但他们使用了一些对我来说不是很有用的其他函数_Next_Node_(/* stuff */)
和_Prev_Node_(/* stuff */)
。谷歌搜索为我提供了有关如何使用擦除功能的有用结果,而不是如何自己编写。
问题:有没有办法可以擦除迭代器指向的元素而不必抓住它的pCurr_成员?
答案 0 :(得分:3)
请勿使用以下划线开头,后跟大写字母的标识符。它们保留给标准库和系统编写器。虽然您正在编写自己的列表类,但实际上并没有编写标准库。
end()通常是列表末尾的一个元素,而不是最后一个元素。 (要获得列表的实际最后迭代器,您可以执行l.rbegin()。base())。
按值传递迭代器,而不是非const引用。
为什么如此关注修改pCurr?
答案 1 :(得分:2)
这并没有真正违反封装。容器及其迭代器紧密耦合几乎是不可避免的。他们两个一起隐藏了用户的实现细节。如果他们不是彼此的朋友,则必须将更多实施细节泄露给用户。 朋友关键字可以增强封装,如果相关课程有正当理由了解彼此的内部结构。
请注意,表示具有一个元素的列表的begin() == end()
不是标准库约定,这意味着容器为空。 end()
应该将迭代器返回到容器的“一个接一个”。