【问题标题】:Custom iterator not dereferencing issue自定义迭代器不取消引用问题
【发布时间】:2017-02-21 09:24:23
【问题描述】:

这是实现std::list<std::vector<char>> 的迭代器的第一次尝试:

Document.h

#ifndef Document_h
#define Document_h

//-------------------------------------------------------------------------

typedef std::vector<char> Line;                                 // line of text

//-------------------------------------------------------------------------

class Text_iterator
{
public:
    Text_iterator(std::list<Line>::iterator l, Line::iterator p)// constructor
        : ln(l), pos(p) { }

    Text_iterator(const Text_iterator& src)                     // copy constructor
        : ln(src.ln), pos(src.pos) { }

    Text_iterator& operator= (const Text_iterator& src)         // copy assignment
    {
        Text_iterator temp(src);
        this->swap(temp);
        return *this;
    }

    char& operator*() { return *pos; }                          // dereferencing

    Text_iterator& operator++ ()                                // incrementation
    {
        ++pos;
        if (pos == ln->end())        
        {
            ++ln;
            pos = ln->begin();
        }
        return *this;
    }

    bool operator== (const Text_iterator& other) const          // comparison
    {
        return ln == other.ln && pos == other.pos;
    }

    bool operator != (const Text_iterator& other) const         // comparison
    {
        return !(*this == other);
    }

    void swap(Text_iterator& src)                               // helper: swap
    {
        std::swap(src.get_line(), ln);
        std::swap(src.get_column(), pos);
    }

    std::list<Line>::iterator get_line() { return ln; }         // accessors
    Line::iterator get_column() { return pos; }                             

private:
    std::list<Line>::iterator ln;                               // data members
    Line::iterator pos;
};

//-------------------------------------------------------------------------

void swap (Text_iterator& lhs, Text_iterator& rhs)              // object swap
{
    lhs.swap(rhs);
}

//-------------------------------------------------------------------------

class Document
{
public:
    typedef Text_iterator iterator;
public:
    Document()                                                  // constructor
    {
        Line l(10, 'a');
        text.push_back(l);
    }

    iterator begin()                                            // iterator to first element
    { 
        return iterator(text.begin(), (*text.begin()).begin());
    }

    iterator end()                                              // iterator to last element
    { 
        return iterator(text.end(), (*text.end()).end());
    }

    void print()
    { 
        for (Document::iterator p = begin(); p != end(); ++p)
        {
            std::cout << *p;
            getchar();
        }
    }

    std::list<Line> text;                                       // data member
};

#endif

main.cpp

#include <iostream>
#include <sstream>
#include <vector>
#include <list>
#include <algorithm>
#include "Document.h"

int main()
{
    Document text;
    text.print();
}

预期输出:

啊啊啊啊啊

我得到的不是上述预期的输出:

调试断言失败
表达式:列表迭代器不可取消引用。

为什么会出现这种行为以及如何纠正它?


注意:经过简短的研究,我发现这种行为的最常见原因是尝试取消引用 end() 迭代器,但我在我的代码中找不到这样的表达式。

【问题讨论】:

  • 您的迭代器需要存储每个容器的结尾以及开头。

标签: c++ list vector iterator


【解决方案1】:

您正在取消引用 Document::end() 中的结束迭代器 *text.end()。最简单的解决方法是使用list::back()(和Document::begin() 中的list::front())。

修复该问题后,您会发现 Text_iterator::operator++ 也会取消引用结束迭代器,因为您不会检查 ln 是否有适当的结束。 @Jonathan Potter 的评论是对的,您需要将text.end() 传递给Text_iterators

变化:

class Text_iterator
{
    // Declarations elided
private:
    std::list<Line>::iterator ln;
    std::list<Line>::iterator ln_end;
    Line::iterator pos;        
}

Text_iterator::Text_iterator(std::list<Line>::iterator l, std::list<Line>::iterator l_end, Line::iterator p)
    : ln(l), ln_end(l_end), pos(p) { }

Text_iterator::Text_iterator(const Text_iterator& src)
    : ln(src.ln), ln_end(src.ln_end), pos(src.pos) { }

Text_iterator& Text_iterator::operator++ ()
{
    ++pos;
    if (pos == ln->end())        
    {
        ++ln;
        if(ln != ln_end)
        {
            pos = ln->begin();
        }
    }
    return *this;
}

void Text_iterator::swap(Text_iterator& src)
{
    std::swap(src.ln, ln);
    std::swap(src.ln_end, ln_end);
    std::swap(src.pos, pos);
}

Document::iterator Document::begin()
{ 
    return iterator(text.begin(), text.end(), text.front().begin());
}

Document::iterator Document::end()
{ 
    return iterator(text.end(), text.end(), text.back().end());
}

当最终自增发生时,pos 将指向最终Line 的结束迭代器,ln 将指向文本的结束迭代器,也就是我们在Document::end() 中传递给Text_iterator 构造函数的内容。我们不需要比较或暴露Text_iterator::ln_end 来保留合理的语义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-14
    • 2021-06-10
    • 2013-12-17
    • 2012-11-08
    • 1970-01-01
    • 2012-10-30
    • 2015-01-13
    • 1970-01-01
    相关资源
    最近更新 更多