我正在编写一个实现双向链接树的类,我希望用户能够尽可能高效地迭代节点的所有子节点。
我遗漏了迭代中没有涉及的所有内容。
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_;
};
现在,我在这里看到两种可能性:
(假设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
}
由于用户无法访问底层结构,因此看起来很简单并且保存。此外,没有太多开销,因为每当修改树时,children_
- 向量的长度都会保存到变量中(只需信任我),并且内联函数来获取此长度。
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:这是我在写这篇文章时提出的第三种方法,但我现在知道如何实现它:
( : )
- 循环for (Tree& child : Tree::root()){
//do stuff with child
}
语法方面,它看起来非常简单,但我不知道for ( : )
- 循环内部实际上做了什么(可能与迭代器一起工作,如果没有->begin()
和{{1在树上的函数。)
奖金问题:是否有可能为我自己的班级实施这种模式?
答案 0 :(得分:2)
正如@WojitekSurowka所说,我调查了boost indirect iterator,这似乎是一个很好的选择。但是,它似乎与VS2013不能很好地协同工作,所以我不得不自己写一个迭代器,这并不像我原先想象的那么难。
根据@JoachimPileborg发布的this reference,这使我能够在其所有荣耀中使用for ( : )
- 循环。但请注意,我的解决方案使用的是一个完全自定义的迭代器,它不是从任何STL向量派生的,因此无法保证正确地与所有STL操作一起使用。
class Tree;
class TreeIterator
{
public:
TreeIterator(std::vector<unique_ptr<Tree>>::iterator& pos) :
pos_(pos)
{};
bool operator==(const TreeIterator& rhs) { return pos_ == rhs.pos_; }
bool operator!=(const TreeIterator& rhs) { return pos_ != rhs.pos_; }
bool operator<=(const TreeIterator& rhs) { return pos_ <= rhs.pos_; }
bool operator>=(const TreeIterator& rhs) { return pos_ >= rhs.pos_; }
bool operator<(const TreeIterator& rhs) { return pos_ < rhs.pos_; }
bool operator>(const TreeIterator& rhs) { return pos_ > rhs.pos_; }
void operator ++(){ ++pos_; }
//this is the most important thing!!!
Tree& operator*(){
return **pos_; //double-dereferencing
}
private:
std::vector<unique_ptr<Tree>>::iterator pos_;
};
class Tree
{
public:
static Tree& root(){ return *root_; }
//regular begin and end functions for iterators, used by the `for( : )`-loop
TreeIterator& begin(){
return *(beginIter_ = std::move(unique_ptr<TreeIterator>(new TreeIterator(children_.begin()))));
}
TreeIterator& begin(){
return *(endIter_ = std::move(unique_ptr<TreeIterator>(new TreeIterator(children_.end()))));
}
private:
vector<unique_ptr<Tree>> children_;
Tree* parent_;
unique_ptr<TreeIterator> beginIter_;
unique_ptr<TreeIterator> endIter_;
static unique_ptr<Tree> root_;
};
所以这使我能够做到以下几点:
for(Tree& child : Tree::root()){
//do stuff with child
}
太棒了!