如何修复声明"矢量下标超出范围"的断言失败



我在发布此问题之前查看的其他问题:

调试断言失败:矢量下标超出范围

调试断言失败矢量下标超出范围C++

我正在进行一个Boids项目,详细信息可以在这里找到:

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

据我所知,我的问题与函数访问索引有关,但索引中没有数据。昨天,我在代码的另一个区域遇到了这个问题,并通过让我的一个getter返回引用而不是类对象的副本来修复它。这种做法似乎不是今天的问题。

以下是我的代码:

这段代码是我处理模拟事件的函数中的一个片段。这是我将问题缩小到的代码。

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

下面的代码来自我的Flock.cpp类定义文件,该文件详细说明了如何将boid存储在向量中,然后将群集行为应用到。这个类函数给出了以下错误:

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

代码:

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

我怀疑for循环大小没有反映出最近擦除的对象。

如何修复矢量下标错误?

编辑:

这是调试器中显示的断点:

_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];
}

编辑2:

我做了一些麻烦,发现只有在调试模式下运行VS 2019时才会出现问题,否则在发布模式下,它可以正常工作,正如预期的那样。

我在这段代码中没有看到任何可能导致越界访问的内容。但是,在任何移除生物体的循环迭代中,都不应增加i,否则将跳过列表中的下一个生物体。

想象一下,在第一次循环迭代中,索引0处的生物体需要删除。随后的生物体在列表中向下移动。在下一次循环迭代中,i增加到1,并且跳过已移动到索引0的生物体。

试试这个:

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

或者,您可以通过std::remove_if()std::vector::erase()使用擦除删除习惯用法来替换整个循环,例如:

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

或者,在C++20中,通过std::erase_if(),例如:

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

要循环通过您正在修改的向量,您不希望在每个循环中使用i++,因为如果删除了元素,则不需要增加索引。对此有两种解决方案,一种是在循环结束时有条件地增加索引,另一种是向后循环列表。

int i = 0;
while (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++;
}
}
for (int i = m_flock.getSize(); i ; i--)
{
if (m_flock.getOrganism(i).getEnergyStore() <= 0)
{
m_flock.removeOrganism(i);
cout << "Organism died and has been removed..." << endl;
}
}

您不能为此使用普通迭代器循环,因为CCD_;使擦除点处或之后的迭代器和引用无效,包括end((迭代器";。但是,您可以使用std::remove_if

m_flock.erase(std::remove_if(m_flock.begin(),
m_flock.end(),
[](Organism org){
return org.getEnergyStore()<=0;
}));

最新更新