如何迭代私有成员std :: vector最有效?

时间:2014-04-09 09:37:17

标签: 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& 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
}

由于用户无法访问底层结构,因此看起来很简单并且保存。此外,没有太多开销,因为每当修改树时,children_ - 向量的长度都会保存到变量中(只需信任我),并且内联函数来获取此长度。

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。 for ( : ) - 循环

for (Tree& child : Tree::root()){
    //do stuff with child
}

语法方面,它看起来非常简单,但我不知道for ( : ) - 循环内部实际上做了什么(可能与迭代器一起工作,如果没有->begin()和{{1在树上的函数。)

奖金问题:是否有可能为我自己的班级实施这种模式?

1 个答案:

答案 0 :(得分:2)

正如@WojitekSurowka所说,我调查了boost indirect iterator,这似乎是一个很好的选择。但是,它似乎与VS2013不能很好地协同工作,所以我不得不自己写一个迭代器,这并不像我原先想象的那么难。

根据@JoachimPileborg发布的this reference,这使我能够在其所有荣耀中使用for ( : ) - 循环。但请注意,我的解决方案使用的是一个完全自定义的迭代器,它不是从任何STL向量派生的,因此无法保证正确地与所有STL操作一起使用。

tree.h中:

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
}

太棒了!