使用引用语义向抽象生成器实现迭代器的正确方法

时间:2014-01-28 18:08:30

标签: c++ templates pointers iterator generator

我有一个产生值的类,其界面如下:

template<class T>
class Generator
{
public:
    void advance();
    T* get();
    bool done();
    //...
};

advance函数使生产者前进并在内部存储中放置一个指向新值的指针。 get函数返回此指针,如果nullptr完成则返回Generator(尽管Generator在正常操作过程中可以生成nullptrs )。如果done完成生成值,Producer将返回true。 get返回一个指针,允许客户端与生成的值进行交互,从而可能将信息传回Generator

对于实现迭代器来说,这似乎非常简单。 Generator类不可复制,因此它本身不能成为迭代器,所以我创建了一个带有nessesary操作的简单包装器。我遇到的问题是后增量算子;推进Generator使旧指针无效。我已经玩过不同的想法,但没有一个允许我满足输入迭代器或输出迭代器的所有要求。我不希望我的迭代器有一个值的副本,因为我希望通过指针有引用语义。我最接近的是让迭代器存储一个增量计数器,并且仅在取消引用或比较操作时提前Generator。这让人感到const_cast,并且感到非常危险。有没有办法为这个接口实现正确的迭代器?

1 个答案:

答案 0 :(得分:1)

根据您的描述,我认为您能做的最好的就是投入 迭代器。前向迭代器的一个保证是 他们是多遍的,我不知道你怎么能这样做 你的班。你的班级不支持记忆职位, 并从它重新启动,所以一旦一个迭代器前进,没有 其他人可以看到那个元素。

当然,你还可以做很多事情 输入迭代器,但如果它们不够,你就必须这样做 使用迭代器将值复制到向量中,然后迭代 在那之上。

编辑:

关于您对*r++工作的必要性的评论: 我认为以下是合法的:

template <typename T>
class GeneratorIterator
{
    class PostIncrProxy
    {
        GeneratorIterator* myOwner;
    public:
        PostIncrProxy( GeneratorIterator* owner )
            : myOwner( owner )
        {
        }
        ~PostIncrProxy()
        {
            ++(*myOwner);
        }
        T* operator*() const
        {
            return **myOwner;
        }
    };

    Generator<T>* myOwner;
public:
    GeneratorIterator( Generator<T>& owner )
        : myOwner( &owner )
    {
    }
    GeneratorIterator()           //  End iterator...
        : myOwner( nullptr )
    {
    }

    bool operator==( GeneratorIterator const& other ) const
    {
        return (myOwner == nullptr) == (other.myOwner == nullptr);
    }
    bool operator!=( GeneratorIterator const& other ) const
    {
        return !operator==( other );
    }

    T* operator*() const
    {
        assert( myOwner != nullptr );
        return myOwner->get();
    }
    //  -> not necessary if we're iterating over T*.  If 

    GeneratorIterator& operator++()
    {
        assert( myOwner != nullptr );
        myOwner->advance();
        if ( myOwner->done() ) {
            myOwner = nullptr;
        }
    }

    PostIncrProxy operator++(int)
    {
        return PostIncrProxy( this );
    }
};

这将推迟实际增量直到结束 完整的表达,我想这可能是一些问题 堕落的案例,但我至少试一试。 (如果更糟 最糟糕的是,你也可以做增量 PostIncrProxy::operator*,一旦你恢复了回报 value,然后将其myOwner设置为null,测试该案例 在析构函数中。)