【问题标题】:Vector iterator not dereferencable向量迭代器不可解引用
【发布时间】:2008-11-19 14:04:47
【问题描述】:

我有一个名为 Shape 的抽象基类,它派生了 Circle 和 Rectangle,但是当我在 VS 2005 中执行以下代码时,我得到错误 Debug assertion failed。同时我没有在任何类中重载 == 运算符

表达式:向量迭代器不可解引用,这是什么原因。

  vector<Shape*> s1;
  s1.push_back(new Circle(point(1,2),3));
  s1.push_back(new Circle(point(4,3),5));
  s1.push_back(new Rectangle(point(1,1),4,5));

  vector<Shape*> s2(s1);
  reverse(s1.begin(),s1.end());

  (*find(s1.begin(),s1.end(),new Circle(point(1,2),3)))->move(point(10,20));

【问题讨论】:

    标签: c++ stl


    【解决方案1】:

    简单:

    • 查找失败,因为无法在矢量中找到您新创建的 Circle 并比较 Shape *
    • 失败的查找返回结束迭代器,该迭代器不能被 Debug 断言捕获

    要让它像你想要的那样工作,你确实需要比较 Shape,而不是 Shape*

    正如其他答案中指出的那样,boost::ptr_vector 是实现这一目标的简单方法。

    【讨论】:

    • 并比较 Shape 对象而不是 Shape Pointer 使用 boost::ptr_vector。这使您可以更自然地使用常规算法。
    【解决方案2】:

    就像@David Pierre 建议的那样:find 是基于值的:它在迭代器范围内查找与您刚刚创建的指向 new Circle(point(1,2),3) 的指针相等的指针(例如 0x0F234420)。因为那是一个新对象,所以它不会在那里。

    您可以通过将find_if 与比较指针所引用的对象的运算符一起使用来解决此问题。

    但是,Criterium 应该能够区分形状类型。

    class Shape {
    public:
        //amongst other functions
        virtual bool equal( const Shape* ) const = 0;
    };
    
    class Circle : public Shape {
    public:
        bool equal( const Shape* pOther ) const {
            const Circle* pOtherCircle = dynamic_cast<const Circle*>( pOther );
            if( pOtherCircle == NULL ) return false;
            // compare circle members
        }
    };
    
    class Rectangle : public Shape {
    public:
        bool equal( const Shape* pOther ) const {
            const Rectangle* pOtherR = dynamic_cast<const Rectangle*>( pOther );
            if( pOtherR == NULL ) return false;
            // compare rectangle members
        }
    };
    
    
    
    Shape* pFindThis = new Circle(point(1,2),3);
    vector<Shape*>::const_iterator itFound = find_if(s1.begin(),s1.end(), 
        bind1st( mem_fun( &Shape::equal ), pFindThis) ) );
    delete pFindThis; //leak resolved by Mark Ransom - tx!
    
    if( itFound != s1.end() ) {
        (*itFound)->move(point(10,20));
    }
    

    【讨论】:

    • bind1st 完成后是否删除第二个参数?如果没有,你有内存泄漏。我想你只是想要一个当地的临时工。
    【解决方案3】:

    这是使用 boost::ptr_vector 的一个很好的理由。

    它不仅可以处理您的对象需要被销毁的事实。
    xtofl@: 你忘了虚拟析构函数。

    但它也通过返回引用而不是指针使成员看起来像对象。这使您可以更自然地使用标准算法,而不是在“equal”函数中摆弄指针(这很不像 C++)。

    #include <boost/ptr_container/ptr_vector.hpp>
    #include <iostream>
    
    class Shape
    {
        public:
            ~Shape()    {}
            bool operator==(Shape const& rhs) const
            {
                if (typeid(*this) != typeid(rhs))
                {
                    return false;
                }
    
                return this->isEqual(rhs);
            }
        private:
            virtual bool isEqual(Shape const& rhs) const    = 0;
    };
    
    class Circle: public Shape
    {
        public:
            Circle(int r)
                :radius(r)
            {}
        private:
            virtual bool isEqual(Shape const& r) const
            {
                Circle const&   rhs = dynamic_cast<Circle const&>(r);
                return radius == rhs.radius;
            }
            int radius;
    };
    class Rectangle: public Shape
    {
        public:
            Rectangle(int h,int w)
                :height(h)
                ,width(w)
            {}
        private:
            virtual bool isEqual(Shape const& r) const
            {
                Rectangle   const&  rhs = dynamic_cast<Rectangle const&>(r);
                 return (height == rhs.height) && (width == rhs.width);
            }
            int height;
            int width;
    };
    
    
    int main()
    {
    
        boost::ptr_vector<Shape>    data;
    
        data.push_back(new Circle(5));
        data.push_back(new Circle(6));
        data.push_back(new Rectangle(7,4));
    
        boost::ptr_vector<Shape>::iterator f;
        f = find(data.begin(),data.end(),Circle(6));
    
        std::cout << "Find(" << (f - data.begin() ) << ")" << std::endl;
    
    
    }
    

    【讨论】:

    • 在调用 isEqual 之前依靠 operator== 来验证形状是否相同似乎有点危险。我更愿意看到 isEqual 本身内部的检查,就像 xtofl 所做的那样。
    • 我更喜欢在 'operator==' 这样代码不会重复。为什么要在 isEqual 中使用它?注意 Shape 是纯虚拟的,不可能有实例。我不明白你为什么认为它是 dangrorus?
    • 我对检查基类中的 typeid 有一个疑问。为什么这实际上是需要的?因为由于多态性,对正确 isEqual 函数的调用在运行时被解析。
    • sirishkumar.myopenid.com@ 我承认这可能是一个早期的优化。但是,如果您不签入 'operator==',那么每个版本的 isEqual() 还需要显式验证类型 'rhs' 参数,需要 dynamic_cast() 并检查 bad_cast 异常或 NULL。跨度>
    猜你喜欢
    • 2011-05-29
    • 1970-01-01
    • 1970-01-01
    • 2013-01-20
    • 2016-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多