C++ 在清除循环中的向量时,如何避免超出范围的异常?
我为冗长的解释道歉C++ 在清除循环中的向量时,如何避免超出范围的异常?,c++,string,vector,while-loop,erase,C++,String,Vector,While Loop,Erase,我为冗长的解释道歉 我正在研究一个C++应用程序,它将两个文件加载到两个2D字符串向量中,重新排列这些向量,再生成另一个2D字符串向量,并将它们全部输出到报表中。这两个向量的第一个元素是一个代码,用于标识项目的所有者和向量中的项目。我在启动时将所有者的标识传递给程序,并通过嵌套while循环中的两个向量进行循环,以找到具有匹配的第一个元素的向量。当我这样做时,我用前两个向量的分量构建第三个向量,然后我需要捕获任何不匹配的向量 当两个原始数组匹配时,我使用语法“vector.erase(vecto
我正在研究一个C++应用程序,它将两个文件加载到两个2D字符串向量中,重新排列这些向量,再生成另一个2D字符串向量,并将它们全部输出到报表中。这两个向量的第一个元素是一个代码,用于标识项目的所有者和向量中的项目。我在启动时将所有者的标识传递给程序,并通过嵌套while循环中的两个向量进行循环,以找到具有匹配的第一个元素的向量。当我这样做时,我用前两个向量的分量构建第三个向量,然后我需要捕获任何不匹配的向量
当两个原始数组匹配时,我使用语法“vector.erase(vector.begin()+I)”从中删除元素。循环完成后,我得到了新的第三个向量,剩下的两个向量只有元素,不匹配,这就是我需要的。当我尝试文件中的不同所有者时(程序一次只接受一个所有者),这工作正常。然后我尝试了一个产生超出范围错误的方法 我不知道如何在不抛出错误的情况下在循环内部执行擦除(似乎swap和pop或eraseremove都不是可行的解决方案)。在构建了第三个向量之后,我用两个额外的嵌套while循环解决了程序的问题 我想知道如何使擦除方法在这里工作(因为它似乎是一个更简单的解决方案),或者至少如何检查超出范围的错误(并避免它)。对于这个特定的所有者,有很多“行”;所以调试是乏味的。在放弃并继续使用嵌套的while解决方案之前,我确定第二次擦除引发了错误。我怎样才能做到这一点,或者说我在事后的努力是我所能做到的最好的吗?代码如下:i = 0;
while (i < AIvector.size())
{
CHECK:
j = 0;
while (j < TRvector.size())
{
if (AIvector[i][0] == TRvector[j][0])
{
linevector.clear();
// Add the necessary data from both vectors to Combo_outputvector
for (x = 0; x < AIvector[i].size(); x++)
{
linevector.push_back(AIvector[i][x]); // add AI info
}
for (x = 3; x < TRvector[j].size(); x++) // Don't need the the first three elements; so start with x=3.
{
linevector.push_back(TRvector[j][x]); // add TR info
}
Combo_outputvector.push_back(linevector); // build the combo vector
// then erase these two current rows/elements from their respective vectors, this revises the AI and TR vectors
AIvector.erase(AIvector.begin() + i);
TRvector.erase(TRvector.begin() + j);
goto CHECK; // jump from here because the erase will have changed the two increments
}
j++;
}
i++;
}
i=0;
而(i
如前所述,您的转到
跳到了错误的位置。只要将它移出第一个循环,而循环就可以解决您的问题。但我们能做得更好吗
可以使用std::remove
和std::erase
干净地从向量中删除对象,这样移动对象就比较便宜,而vector
和string
都是。然而,经过一番思考,我认为这并不是最好的解决方案,因为您需要一个函数,它不仅可以检查两个容器中是否存在某一行,而且不容易用erase-remove习惯用法来表示
保留当前结构后,我们可以对循环条件使用迭代器。我们可以从中获得很多好处,因为std::vector::erase
将迭代器返回到被删除元素之后的下一个有效元素。更不用说它需要一个迭代器。有条件地擦除向量中的元素变得非常简单
auto it = vec.begin()
while (it != vec.end()) {
if (...)
it = vec.erase(it);
else
++it;
}
因为我们将erase
的返回值赋值给it
,所以我们不必担心迭代器失效。如果我们删除最后一个元素,它将返回vec.end()
,因此不需要特殊处理
您的第二个循环可以完全删除。C++标准定义了用于在STL容器中搜索的函数。code>std::find_if
搜索满足条件的容器中的值并向其返回迭代器,或者end()
搜索不存在的值。您还没有在任何地方声明您的类型,所以我将假设行是std::vector>
提示:除了erase
方法外,不使用向量特定功能,您可以在每次迭代中删除相同的索引,同时检查大小。您的实际问题不清楚。如果您想知道如何避免在没有GOTO的情况下实现类似的东西,那么很简单,将代码重构为两部分。第一部分是一个使用嵌套循环搜索数组的函数,如果找到匹配项,则生成的索引将获得return
ed,并在while
循环中自动断开;第二部分重复调用第一个函数,如果第一个函数找到匹配项,则从两个数组中移除匹配元素,然后重试;或在第一个函数未找到匹配项时停止。结尾。检查
不应该在第一个之外,而
?当您擦除AIVector
的最后一个元素,然后转到检查时会发生什么情况代码>?请看一下函数,特别是erase-remove示例,以获得一种更简洁、更惯用的方法来处理此类问题。谢谢您的评论。我想我需要多读一些。我是一个上了年纪的C程序员;所以我发现一些C++语法有点压倒了。帕塔流氓,你说得对。如果我使用goto,我就找错地方了。我把它移到了第一次的上方,我的超出范围的错误消失了。不过,我认为我在这里所做的不是
using row_t = std::vector<std::string>;
auto AI_it = AIVector.begin();
while (AI_it != AIVector.end()) {
// Find a row in TRVector with the same first element as *AI_it
auto TR_it = std::find_if (TRVector.begin(), TRVector.end(), [&AI_it](const row_t& row) {
return row[0] == (*AI_it)[0];
});
// If a matching row was found
if (TR_it != TRVector.end()) {
// Copy the line from AIVector
auto linevector = *AI_it;
// Do NOT do this if you don't guarantee size > 3
assert(TR_it->size() >= 3);
std::copy(TR_it->begin() + 3, TR_it->end(),
std::back_inserter(linevector));
Combo_outputvector.emplace_back(std::move(linevector));
AI_it = AIVector.erase(AI_it);
TRVector.erase(TR_it);
}
else
++AI_it;
}
auto linevector = Combo_outputvector.back();