1

I implemented a trivial class MyClass that has an array allocated with new inside it (I know that I could use a STL container, but I'm trying to understand how they work). I also created an iterator subclass, able to iterate on all the elements of a MyClass object:

class MyIterator : public iterator<forward_iterator_tag,int>
{
private:
    int* data= nullptr;
    int length;
    int pointer=0;
    int nullvalue=0;
public:
    MyIterator(int* data, int length, bool end= false)
    {
        this->data= data;
        this->length= length;
        if(end)
            pointer=-1;
    }
    ~MyIterator()
    {
        delete[] data;
    }
    MyIterator& operator++()
    {
        if(pointer!= length-1)
        {
            pointer++;
        }
        else
        {
            pointer= -1;
        }
        return *this;
    }
    bool operator==(const MyIterator& other)
    {
        return pointer==other.pointer;
    }
    bool operator!=(const MyIterator& other)
    {
        return pointer!= other.pointer;
    }
    int& operator* ()
    {
        if(pointer==-1)
            return nullvalue;
        else
            return data[pointer];
    }
};

class MyClass
{
private:
    int* data= nullptr;
    int length= 100;
public:
    MyClass()
    {
        data= new int[length];
        for(int i=0; i<length;i++)
            data[i]=i+1;
    }
    iterator<forward_iterator_tag,int> begin()
    {
        return MyIterator(data,length);
    }
    iterator<forward_iterator_tag,int> end()
    {
        return MyIterator(data,length,true);
    }
};

While the iterator works if I use it this way:

for(MyIterator i= MyClass_instance.begin(); i!=MyClass_instance.end();i++) {...}

It doesn't work if I try to use it with BOOST_FOREACH:

BOOST_FOREACH(int i, MyClass_instance) {...}

These are the errors that I get:

enter image description here

4

1 回答 1

3
  • 您通过将迭代器作为std::iterator<> 按值返回来对迭代器进行切片。你不能这样做。

    通过引用返回将避免切片问题,但会引入更糟糕的问题:它返回对临时的引用¹。

    因此,通过按值返回您的实际迭代器类型来修复它。

  • 您的类型缺少 const 迭代器。

  • 所有迭代器成员都不是 const 正确的。

  • 此外,根据页面可扩展性,您似乎需要添加

    namespace boost {
        template<> struct range_mutable_iterator<MyClass> {
            typedef MyClass::MyIterator type;
        };
    
        template<> struct range_const_iterator<MyClass> {
            typedef MyClass::MyConstIterator type;
        };
    }
    
  • 您的迭代器类型的三规则实现存在严重问题(三规则是什么?)。

    每次迭代器不存在时,您都会删除容器的数据。而且MyClass它本身永远不会释放数据......

修复上述大部分(?):

Live On Coliru

#include <iterator>
#include <boost/foreach.hpp>

class MyClass
{
private:
    int* data  = nullptr;
    int length = 100;

public:
    class MyIterator : public std::iterator<std::forward_iterator_tag, int>
    {
        public:
            MyIterator(int* data, int length, bool end = false)
            {
                this->data= data;
                this->length= length;
                if(end)
                    pointer=-1;
            }
            MyIterator& operator++()
            {
                if(pointer!= length-1) {
                    pointer++;
                }
                else {
                    pointer= -1;
                }
                return *this;
            }

            bool operator==(const MyIterator& other) const { return pointer==other.pointer; }
            bool operator!=(const MyIterator& other) const { return pointer!= other.pointer; }
            int& operator*() const
            {
                if(pointer==-1)
                    return nullvalue;
                else
                    return data[pointer];
            }
        private:
            value_type* data     = nullptr;
            int length;
            int pointer          = 0;
            mutable value_type nullvalue = 0;
    };

    class MyConstIterator : public std::iterator<std::forward_iterator_tag, const int>
    {
        public:
            MyConstIterator(int const* data, int length, bool end = false)
            {
                this->data= data;
                this->length= length;
                if(end)
                    pointer=-1;
            }
            MyConstIterator& operator++()
            {
                if(pointer!= length-1) {
                    pointer++;
                }
                else {
                    pointer= -1;
                }
                return *this;
            }

            bool operator==(const MyConstIterator& other) const { return pointer==other.pointer; }
            bool operator!=(const MyConstIterator& other) const { return pointer!= other.pointer; }
            int const& operator*() const
            {
                if(pointer==-1)
                    return nullvalue;
                else
                    return data[pointer];
            }
        private:
            value_type* data     = nullptr;
            int length;
            int pointer          = 0;
            value_type nullvalue = 0;
    };

public:
    typedef MyIterator iterator_type;
    typedef MyConstIterator const_iterator_type;

    MyClass()
    {
        data= new int[length];
        for(int i=0; i<length;i++)
            data[i]=i+1;
    }
    ~MyClass() {
        delete[] data;
    }
    iterator_type begin()             { return MyIterator(data,length);      }
    iterator_type end()               { return MyIterator(data,length,true); }
    const_iterator_type begin() const { return MyConstIterator(data,length);      }
    const_iterator_type end()   const { return MyConstIterator(data,length,true); }
};

namespace boost {
    template<> struct range_mutable_iterator<MyClass> {
        typedef MyClass::MyIterator type;
    };

    template<> struct range_const_iterator<MyClass> {
        typedef MyClass::MyConstIterator type;
    };
}

#include <iostream>

int main()
{
    MyClass c;
    BOOST_FOREACH(int i, c) {
        std::cout << i << "\n";
    }
}

¹(除非您将迭代器存储在其他地方,但由于许多原因,这将是一个巨大的反模式)

于 2014-12-21T21:13:09.653 回答