首页 > 解决方案 > How can I fix an assertion failure that states 'vector subscript out of range'

问题描述

Other questions that I viewed before posting this question:

Debug Assertion Failed: Vector subscript out of range

Debug Assertion Failed Vector Subscript Out of Range C++

I am working on a Boids project, details of which can be found here:

https://www.red3d.com/cwr/boids/

From what I can gather my issue is something to do with an index getting accessed by the function but no data is present in the index. I had this issue yesterday in a different area of my code and fixed it by making one of my getters return a reference rather than a copy of a class object. That approach seems to not be the issue today.

Below is my code:

This code is a snippet from my function that handles simulation events. This is the code that I have narrowed down the issue to.

//Remove flocking organisms with < 0 enery storage.
for (int i = 0; i < m_flock.getSize(); i++)
{
    if (m_flock.getOrganism(i).getEnergyStore() <= 0)
    {
        m_flock.removeOrganism(i);
        //m_notFlocking.flock.erase(m_notFlocking.flock.begin() + i);
        cout << "Organism died and has been removed..." << endl;
    }
}

The code below is from my Flock.cpp class definition file which details information on storing boids in a vector to then apply flocking behaviors to. This class function is giving the following error:

Unhandled exception at 0x7B87FC66 (ucrtbased.dll) in EvoSim.exe: An invalid parameter was passed to a function that considers invalid parameters fatal.

Code:

Organism &Flock::getOrganism(int i)
{
    return flock[i];
}

My suspicion is that the for loop size is not reflecting the recently erased object.

How can I fix the vector subscript error?

Edit:

This is the break point that shows up in the debugger:

    _NODISCARD _Ty& operator[](const size_type _Pos) noexcept /* strengthened */ {
        auto& _My_data = _Mypair._Myval2;
#if _CONTAINER_DEBUG_LEVEL > 0
        _STL_VERIFY(
            _Pos < static_cast<size_type>(_My_data._Mylast - _My_data._Myfirst), "vector subscript out of range");
#endif // _CONTAINER_DEBUG_LEVEL > 0

        return _My_data._Myfirst[_Pos];
    }

Edit 2:

I did some messing around and discovered the issue only occurs when I run VS 2019 in debug mode, otherwise in Release mode it works fine and as expected.

标签: c++

解决方案


I see nothing in this code that can cause an out of bounds access. However, you should not increment i on any loop iteration that removes an organism, otherwise you will skip the next organism in the list.

Imagine on the 1st loop iteration, the organism at index 0 needs to be removed. Subsequent organisms move down the list. On the next loop iteration, i gets incremented to 1, and the organism that had moved into index 0 is skipped.

Try this instead:

//Remove flocking organisms with < 0 enery storage.
for (int i = 0; i < m_flock.getSize(); )
{
    if (m_flock.getOrganism(i).getEnergyStore() <= 0)
    {
        m_flock.removeOrganism(i);
        cout << "Organism died and has been removed..." << endl;
    }
    else
        ++i;
}

Alternatively, you can replace the entire loop using the erase-remove idiom via std::remove_if() and std::vector::erase(), eg:

void Flock::removeDeadOrganisms()
{
    //Remove flocking organisms with < 0 enery storage.
    flock.erase(
        std::remove_if(flock.begin(), flock.end(),
          [](const auto &o){ return o.getEnergyStore() <= 0; }
        ),
        flock.end()
    );
}

...

m_flock.removeDeadOrganisms();

Or, in C++20, via std::erase_if(), eg:

void Flock::removeDeadOrganisms()
{
    //Remove flocking organisms with < 0 enery storage.
    std::erase_if(flock,
        [](const auto &o){ return o.getEnergyStore() <= 0; }
    );
}

推荐阅读