迭代时修改设置可让我segfault

Modifying set while iterating gives me segfault

本文关键字:segfault 设置 修改 迭代      更新时间:2023-10-16

我当前正在处理一个功能,可以使用 int 的向量。我希望我的函数 merge()合并所有共享INT的集合,例如,我希望发生这种情况:

  [0]  -  0, 1, 2                              
  [1]  -  1, 3            Then it will              [0]  -  0, 1, 2, 3
  [2]  -  0, 3            output this vector ->     [1]  -  4, 5
  [3]  -  4, 5                                      [2]  -  6, 7, 8, 9
  [4]  -  6, 7, 8                                   
  [5]  -  8, 9  

我已经编写了此功能,其中介绍了哪个代码。我几乎已经评论了每一行,因此不难理解我的代码!

// Merges all sets that shares at least one int
//
// PARAMETERS...
//      vectorE         : vector of sets of int
void mergeStates( std::vector< std::set< int > >& vectorE )
{
    // For every set of ints
    for( auto &currentSet : vectorE )
    {
        // For every ints of the set
        for( auto currentInt : currentSet )
        {   
            // The two for( ) loops down there allow me to iterate over 
            // every int of every set of the vectorE
            for( auto setToCheck : vectorE )
            {
                // If the set is different from the one we're already targeting
                if( currentSet != setToCheck )
                {
                    for( auto intToCheck : setToCheck )
                    {
                        // if we have found an int that is the same as the one we're targeting
                        if( intToCheck == currentInt )
                        {
                            // Merge
                            etatsetEtudie.insert( setToCheck.begin(), setToCheck.end() );
                            // Deleting the set we copied from, because we won't need it anymore
                            for(auto setToErase = vectorE.begin() ; setToErase != vectorE.end() ; ){
                                if( *setToErase == setToCheck )
                                    setToErase = vectorE.erase( setToErase );
                                else
                                    ++setToErase;
                            }
                        }
                    }
                }
            }
        }
    }
}

每次运行程序时,我都会在删除我们从哪里复制的集合时得到一个segfault:我的错误在哪里?

编辑:我让它工作!

好吧,谢谢,我只是制作了我的参数const并添加了一个返回值,以便我可以动态地添加我需要的每个构造集,然后返回此向量: - )

问题没有修改任何集,它正在修改向量。

从矢量中删除某些东西会在其之后移动元素。首先,这意味着在擦除位置(内部内部使用迭代器使用的迭代器)之后进入向量的迭代器不再有效。其次,如果复制和覆盖集合(而不是移动它们),则所有迭代器都将不再有效。

结果是您的代码中有很多未定义的行为。

另外,即使方法有效,您的最内向循环也不是擦除该集合的好方法。这非常非常低效。

您至少需要重新考虑擦除元素的方式。但是我认为,提出一种更好的算法将是更好的方法。

尝试制作一个新的向量,而不是修改原始矢量:

std::vector<std::set<int>> mergeStates(const std::vector<std::set<int>> & vectorE ) {
    std::vector<std::set<int>> new_vector;
    ...
    return new_vector;
}

您正在使用std :: vector :: erase函数,无效 iterators。因此,基于循环的范围内的代码试图访问容器端的迭代器。

基于范围的 for使用的末端迭代器是在循环之前确定的。由于您在迭代期间erase(),因此结束实际上会发生变化。从erase()的结果中获得迭代器是不足的,因为末端也发生了变化。我认为您可以不使用基于范围的 for循环来删除的范围。