范围之外的矢量擦除迭代器

Vector erase iterator outside of range

本文关键字:擦除 迭代器 范围      更新时间:2023-10-16

链接到项目我正在创建一个小型的过剩应用程序,该应用程序将绘制电路组件。我有一个名为"组件"的类,看起来像这样:

// 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;}

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

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();
}

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

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

只需在堆栈上创建组件,将它们添加到您的向量中,您就会没事的。

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

int Component::nextIndex = 1;

应该是

int Component::nextIndex = 0;

但无论如何,这是一个设计错误;当您从std::vector中删除组件时,您必须更新位于已删除组件之后的组件的所有索引(您需要将它们的值减少 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;
您在

索引Component对象时遇到了一些问题。

首先,向量的索引就像数组,即基于零。因此,如果你有一个只有一个元素的向量,索引(以及begin()迭代器的偏移量)为。其他任何事情都是越界的。

您似乎有一个用于下一个索引的static成员变量,并且您将该变量初始化为1该变量始终是向量中的第一个索引错误。然后在 Component 构造函数中增加此静态nextIndex变量,导致您创建的第二个对象具有索引2但在向量中它将具有索引1(如果向量中同时具有两个对象)。

当您从矢量中删除对象时,会出现另一个问题。除了使用错误索引的(现在很明显的)问题之外,您不会对向量中的索引进行重新编号。因此,如果您在向量中有两个元素具有(错误的)索引 12 ,并删除第一个,那么新的第一个元素将具有更错误的索引2

我解决这个问题的建议是根本不使用索引,而是实现一个相等的比较运算符。然后你可以使用例如 std::find在向量中查找对象,然后使用 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();
}