C++ 如何最有效地迭代私有成员std::vector?
我正在编写一个实现双链接树的类,我希望用户能够尽可能高效地迭代节点的所有子节点 Tree.h(缩写): 我遗漏了迭代中未涉及的所有内容C++ 如何最有效地迭代私有成员std::vector?,c++,for-loop,stl,indexing,iterator,C++,For Loop,Stl,Indexing,Iterator,我正在编写一个实现双链接树的类,我希望用户能够尽可能高效地迭代节点的所有子节点 Tree.h(缩写): 我遗漏了迭代中未涉及的所有内容 class Tree { public: static Tree& root(){ return *root_; } //index-based iteration inline unsigned int numChildren() const{ return childrenSize_; } Tree& getC
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_;
};
这看起来既危险又丑陋,但我可以想象它会更快。我这里的问题是,用户只需将unique_ptr移动到其他地方,我希望尽可能限制使用,以避免错误使用该结构
更有效的方法是什么?它到底有多大区别
PS:这是我在撰写本文时提出的第三种方法,但我现在知道了如何实现它: 3.for
(:)
-循环
语法方面,它看起来非常简单,但我不知道(:)-循环的在内部真正做了什么(可能与迭代器一起工作,如果没有树上的->begin()
和->end()
函数,就无法工作)
额外问题:有可能在我自己的类中实现这个模式吗?正如@WojitekSurowka所建议的,我研究了这个模式,它似乎是一个很好的选择。然而,它似乎不能与VS2013一起很好地工作,所以我不得不自己编写一个迭代器,这并不像我最初想象的那么难
根据@JoachimPileborg发布的消息,这使我能够使用(:)
-循环的。但是,请注意,我的解决方案使用了一个完全自定义的迭代器,它不是从任何STL向量派生的,因此不能保证正确处理所有STL操作
Tree.h:
太棒了 有关基于范围的For循环,请参见例如。它还显示了一个等效的实现。我认为,使用它是首选的替代方法。“…开销不大,因为每当树被修改时,子向量的长度都会保存到一个变量中(请相信我),并且获取此长度的函数是内联的。”-抱歉,不能相信你<代码>矢量
记录其当前大小并支持O(1)内联查询。。。重复会降低性能。更一般地说,Joachim的权利——只需提供begin()
和end()
,人们就可以使用范围来表示;如果需要,迭代器可以隐藏唯一\u ptr
。也可以很容易地支持@JoachimPileborg这个参考资料只表明我的想法行不通,因为儿童
是私有的(应该保持这种方式),我会再次向用户公开独特的ptr
,这并不是真正的想法。糟糕。@TonyD我该如何实现begin()
和end()
函数?你能给我指出它的来源吗?@ifrelicht:“引用仅显示…”-只需将vector::iterator children\u begin()
重命名为begin()
,children\u end()
为一种简单的方法,或者编写自己的迭代器
类以实现更好的封装-它应该存储一个向量::迭代器
,并且解引用生成树&
,而不是唯一的\u ptr
。
Tree& myTree = Tree::root();
for(int i = 0; i < myTree.numChildren(); ++i;){
Tree& child = myTree.getChild(i);
//do stuff with child
}
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
}
for (Tree& child : Tree::root()){
//do stuff with child
}
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
}