代码之家  ›  专栏  ›  技术社区  ›  Georgi Koemdzhiev

矢量擦除迭代器超出范围[已关闭]

  •  -2
  • Georgi Koemdzhiev  · 技术社区  · 8 年前

    link 到项目 我正在创建一个小的过剩应用程序,它将绘制电路组件。 我有一个名为“Component”的类,看起来像这样:

    // nextIndex is the index of the next component to be created
    int Component::nextIndex = 0;
    Component::Component( void ){
    setType( RESISTOR );
    setValue( 0.0 );
    setX( 0.0 );
    setY( 0.0 );
    setSize( 2.0 );
    setIndex( nextIndex );
    }
    
    eType Component::getType( void ){return cType}
    double Component::getValue( void ){return cValue;}
    double Component::getX( void ){return cX;}
    double Component::getY( void ){return cY;}
    double Component::getSize( void ){return cSize;}
    void Component::setType( eType type ){cType = type;}
    void Component::setValue( double value ){cValue = value;}
    void Component::setX( double x){cX = x;}
    void Component::setY( double y ){cY = y;}
    void Component::setSize( double size ){cSize = size;}
    int Component::getIndex( void ){return index;}
    void Component::setIndex( int n ){index = n;}
    

    注意:每次创建类的新实例时,我都会递增nextIndex。 这是我的另一个类,它有一个Components向量,处理组件的添加和删除:

    class OGWindow{
    private:
    
        bool LINK, DELETE;
        int linkNo;
        ...
        Component currentSquare;
        Component *currentSquarePtr, *linkSquPtr1, *linkSquPtr2;
        double squareXStart, squareYStart, squareXEnd, squareYEnd;
        std::vector< Component > compVector;
    
    public:
        ...
        void myMouseClick(int button, int state, int x, int y);
        ...
        void deleteSquare( Component *squPtr );
    };
    

    我正在为窗口创建组件,如下所示: int NEXT_int=0;

    if (x >= createButtonX && x <= createButtonX + createButtonWidth) {
        cout << "Clicked Create button" << endl;
        Component *compPtr = new Component;
        compPtr->setX(0.0);
        compPtr->setY(0.0);
        compPtr->setIndex(NEXT_INT);
        NEXT_INT++;
    
        compVector.push_back(*compPtr);
        //------------SET THE CURRENT SQUARE TO THE NEWLY CREATED COMPONENT-----
        vector<Component>::iterator constIterator;
        for (constIterator = compVector.begin(); constIterator != compVector.end(); ++constIterator){
            currentSquarePtr = &(*constIterator);
        }
        cout << "Vector size:  " << compVector.size() << endl;
        glutPostRedisplay();
    }
    

    但当我删除时,它会删除一些元素,最后一个我会得到“向量超出范围”错误:

    void OGWindow::deleteSquare( Component *squPtr ) {
        compVector.erase(compVector.begin() + (squPtr->getIndex()));
    cout << "Vector size:  " << compVector.size() << endl;
    glutPostRedisplay();
    }
    

    请分享为什么会发生这种情况的任何想法。

    2 回复  |  直到 8 年前
        1
  •  1
  •   rwols    8 年前

    创建组件时会发生大量内存泄漏。您在堆上分配一个新组件,然后将其副本放入 std::vector 。在作用域退出后,指向堆上新组件的指针将永远丢失。

    只需在堆栈上创建组件,将它们添加到向量中,就可以了。

    此外,索引从0开始,而不是从1开始:

    int Component::nextIndex = 1;
    

    应该是

    int Component::nextIndex = 0;
    

    但无论如何,这是一个设计错误;从 std::矢量 ,您必须更新 全部的 位于已删除组件之后的组件的索引(您需要将其值减少1)。

    如果您开始考虑迭代器而不是指针,那会更好。我猜你想要的是:一个巨大的全球数据结构,所有组件都驻留在其中。这可能是一个 std::list<Component> compList 。然后忘记管理索引和指针,并使用 std::list<Component>::iterator 到处都是 Component* 。移除组件是安全的,只需执行以下操作

    void OGWindow::deleteSquare( std::list<Component>::iterator squPtr ) {
        compList.erase(squPtr);
        cout << "List size:  " << compList.size() << endl;
        glutPostRedisplay();
    }
    

    并添加组件

    if (x >= createButtonX && x <= createButtonX + createButtonWidth) {
        cout << "Clicked Create button" << endl;
        Component comp;
        comp.setX(0.0);
        comp.setY(0.0);
    
        // Notice how we put the new component at the front
        // instead of the back.
        compList.push_front(comp);
    
        //------------SET THE CURRENT SQUARE TO THE NEWLY CREATED COMPONENT-----
        // easy now!
        currentSquarePtr = compList.begin();
    
        cout << "List size:  " << compList.size() << endl;
        glutPostRedisplay();
    }
    

    记住,改变这些

    Component *currentSquarePtr;
    Component *linkSquPtr1;
    Component *linkSquPtr2;
    

    这些

    std::list<Component>::iterator currentSquarePtr;
    std::list<Component>::iterator linkSquPtr1;
    std::list<Component>::iterator linkSquPtr2;
    
        2
  •  1
  •   Some programmer dude    8 年前

    您在索引 Component 物体。

    首先,向量的索引类似于数组,即基于零。因此,如果你有一个只有一个元素的向量 begin() 迭代器)是 。其他的都是越界的。

    你似乎有一个 static 用于下一个索引的成员变量,然后将该变量初始化为 1 这将永远是向量中错误的第一索引。然后在 组成部分 构造函数,您可以增加这个静态 nextIndex 变量导致创建的第二个对象具有索引 2 但在向量中它将有索引 1. (如果向量中有两个对象)。

    从向量中移除对象时会出现另一个问题。除了使用错误索引的问题(现在很明显),您不需要在向量中重新编号索引。因此,如果向量中有两个元素的索引(错误) 1. 2. ,并删除第一个元素,则新的第一个元素将具有更错误的索引 2. .

    我建议解决这个问题的方法是完全不使用索引,而是实现一个相等的比较运算符。然后您可以使用例如。 std::find 找到向量中的对象,然后调用 erase 返回正确的迭代器 标准::查找 .

    然后 deleteSquare 看起来会像

    void OGWindow::deleteSquare( Component const &squRef ) {
        auto iterator = std::find( std::begin(compVector), std::end(compVector), squRef);
    
        if (iterator != std::end(compVector))
            compVector.erase(iterator);
    
        cout << "Vector size:  " << compVector.size() << endl;
        glutPostRedisplay();
    }