【发布时间】:2014-05-22 09:57:10
【问题描述】:
我正在编写一个实现双向链接树的类,我希望用户能够尽可能高效地迭代节点的所有子节点。
Tree.h(缩短):
我省略了迭代中不涉及的所有内容。
class Tree
{
public:
static Tree& root(){ return *root_; }
//index-based iteration
inline unsigned int numChildren() const{ return childrenSize_; }
Tree& getChild(unsigned int index) const;
//iterator-based iteration
vector<unique_ptr<Tree>>::iterator children_begin(){
return children_.begin();
}
vector<unique_ptr<Tree>>::iterator children_end(){
return children_.end();
}
private:
vector<unique_ptr<Tree>> children_;
unsigned int childrenSize_;
Tree* parent_;
static unique_ptr<Tree> root_;
};
现在,我在这里看到了两种可能性:
1。基于索引的迭代
(假设static unique_ptr<Tree> root已经构造好了)
Tree& myTree = Tree::root();
for(int i = 0; i < myTree.numChildren(); ++i;){
Tree& child = myTree.getChild(i);
//do stuff with child
}
这看起来很简单并且可以保存,因为用户无法访问底层结构。此外,没有太多开销,因为每当修改 Tree 时,children_-vector 的长度都会保存到一个变量中(请相信我),并且内联获取此长度的函数。
2。基于迭代器的迭代
Tree& myTree = Tree::root();
for(vector<unique_ptr<Tree>>:iterator it = myTree.children_begin(); it < myTree.children_end(); ++it; ){
Tree& child = (*(*it));
//do stuff with child
}
这看起来既危险又丑陋,但我可以想象它会更快。我的问题是用户可以将 unique_ptr 移动到其他地方,我想尽可能限制使用以避免错误使用结构。
什么是更有效的方法,它真的有多大的不同?
PS:这是我在写这篇文章时想到的第三种方法,但我现在知道如何实现它:
3。对于( : )-loop
for (Tree& child : Tree::root()){
//do stuff with child
}
语法方面,它看起来非常简单,但我不知道for ( : )-loop 真正在内部做什么(可能与迭代器一起使用,如果没有->begin() 和->end() Tree 上的函数,则无法使用) .
额外问题:是否可以为我自己的班级实现这种模式?
【问题讨论】:
-
对于基于范围的 for 循环,请参见例如this reference。它还显示了一个等效的实现。我认为使用它是首选的替代方法。
-
"...没有太多开销,因为只要修改了 Tree,children_-vector 的长度就会保存到一个变量中(相信我)和函数这个长度是内联的。” - 对不起,不能相信你。
vector记录它们当前的大小并支持 O(1) 内联查询...重复会降低性能。更一般地说,Joachim 是对的——只需提供begin()和end(),人们可以使用 range-for 表示法;如果需要,您的迭代器可以隐藏unique_ptr。也可以轻松支持visitation function -
@JoachimPileborg This reference仅表明我的想法行不通,因为
children_是私有的(应该保持这种状态),我将再次向用户公开unique_ptrs,这不是真的。无赖。 -
@TonyD 我将如何实现
begin()和end()函数?你能指出我的来源吗? -
@iFreilicht: "reference only shows..." - 只需将
vector<unique_ptr<Tree>>::iterator children_begin()重命名为begin(),children_end()重命名为end()即可,或者编写自己的Iterator类为了更好地封装 - 它应该存储vector<...>::iterator并取消引用产生Tree&,而不是unique_ptr。
标签: c++ for-loop stl indexing iterator