【问题标题】:What is happening with vector array here?这里的向量数组发生了什么?
【发布时间】:2019-06-02 12:51:58
【问题描述】:

我正在通过 C++ 中的 ACO 实现来解决旅行商问题。但是,我发现到目前为止我构建的程序出现了分段错误。 (注意:出于调试目的,我将算法限制为只对菌落进行一次迭代)。

首先,我从一个文件中一共提取了 52 个城市,然后我将蚂蚁分配给每个城市,从它开始每个城市的蚂蚁数量相同。

为了存储每对城市之间的距离,我使用了一个称为 Map(方阵)的双精度向量向量。但是,在执行过程中,这些向量似乎被删除了。在这种情况下,它发生在计算 55 号蚂蚁的路径时。我添加了一段代码只是为了突出显示它崩溃的确切位置:

//DEBUGGING SECTION
                cout << "Size Roulette: " << Roulette.size() << endl;
                cout << "Size Remain: " << RemainingCities.size() << endl;
                cout << "Size Map: " << Map.size() << " x " << Map[0].size() << endl;

                int k = 0;
                cout << "Test: Map access: " << endl;
                for(int i = 0; i < Map.size(); ++i) //  HERE IT CRASHES AT ANT NUMBER 55
                    cout << Map[0][i] << " ";
                cout << endl;

                cout << "Test: Operation: " << Map[Colony[ant_i][city_i-1]][RemainingCities[k]] << endl;

                Roulette[k] = pow((MAX_DIST - Map[Colony[ant_i][city_i-1]][RemainingCities[k]]), heur_coef) + pow((pheromones[Colony[ant_i][city_i-1]][RemainingCities[k]]), pher_coef);

//END OF DEBUGGING SECTION

在那里,函数 Map[0].size() 通常返回 52(就像 Map.size(),因为它应该是一个方阵),但是在崩溃的迭代中它返回看起来像一个内存地址的东西,而当我尝试访问任何元素时,就会发生分段错误。

我检查了内存访问是否始终正确,并且我可以访问任何其他变量,除了 Map 直到第 55 只蚂蚁。 我为轮盘赌方法尝试了不同的种子,但它总是在同一个地方崩溃。

我还改变了蚁群的数量。如果每个城市只有一只蚂蚁,程序可以毫无问题地执行,但如果数量更多,程序总是在第 55 只蚂蚁时崩溃。

您可以从 github 下载完整的 cpp 文件和正在读取的 .tsp 文件:

https://github.com/yitosmash/ACO

无论如何,我将在这里留下完整的功能:

void ACO(const vector<City>& cities, const vector<vector<double>>& Map, int max_it, int num_ants, double decay, double heur_coef, double pher_coef, double pher_coef_elit)
{

        srand(30);

    //Initialise colony of ants (each ant is a vector of city indices)
    vector<vector<int>> Colony(num_ants, vector<int>(cities.size(), 0));

    //Initialise pheromone matrix
    vector<vector<double>> pheromones(cities.size(), vector<double>(cities.size(), 0));
    //Initialise costs vector(for etilist expansion)
    vector<double> costs(cities.size(), 0);

    //Auxiliar vector of indices
    vector<int> cityIndices(cities.size());
    for (int i = 0; i < cities.size(); ++i)
        cityIndices[i] = i;

    //Longest distance from Map, used for heuristic values.
    vector<double> longests(cities.size(), 0);
    for(int i = 0; i < cities.size(); ++i)
        longests[i] = *(max_element(Map[i].begin(), Map[i].end()));

    const double MAX_DIST = *(max_element(longests.begin(), longests.end()));
    longests.clear();


    int i=0;
    while(i<max_it)
    {
        for(int ant_i = 0; ant_i < num_ants; ++ant_i)
        {
            cout << "Ant: " << ant_i << endl;
            //City for ant_i to start at; each ant is assigned a determined starting city
            int starting_city = (int) ((float)ant_i/num_ants*cities.size());
            //cout << starting_city << endl;
            Colony[ant_i][0] = starting_city;

            //Get a vector with the cities left to visit
            vector<int> RemainingCities = cityIndices;

            //Remove starting city from remaining cities
            RemainingCities.erase(RemainingCities.begin() + starting_city);

            //Create path for ant_i
            for(int city_i = 1; city_i < Colony[ant_i].size(); ++city_i)
            {
                cout << "Calculating city number: " << city_i << endl;
                //Create roulette for next city selection
                vector<double> Roulette(RemainingCities.size(), 0);
                double total = 0;

                //DEBUGGING SECTION
                cout << "Size Roulette: " << Roulette.size() << endl;
                cout << "Size Remain: " << RemainingCities.size() << endl;
                cout << "Size Map: " << Map.size() << " x " << Map[0].size() << endl;

                int k = 0;
                cout << "Test: Map access: " << endl;
                for(int i = 0; i < Map.size(); ++i) //  HERE IT CRASHES AT ANT NUMBER 55
                    cout << Map[0][i] << " ";
                cout << endl;

                cout << "Test: Operation: " << Map[Colony[ant_i][city_i-1]][RemainingCities[k]] << endl;

                Roulette[k] = pow((MAX_DIST - Map[Colony[ant_i][city_i-1]][RemainingCities[k]]), heur_coef) + pow((pheromones[Colony[ant_i][city_i-1]][RemainingCities[k]]), pher_coef);

                //END OF DEBUGGING SECTION

                for(int j = 0; j < RemainingCities.size(); ++j)
                {
                    //Heuristic value is MAX_DIST - current edge.
                    Roulette[j] = pow((MAX_DIST - Map[Colony[ant_i][city_i-1]][RemainingCities[j]]), heur_coef) + pow((pheromones[Colony[ant_i][city_i-1]][RemainingCities[j]]), pher_coef);
                    total += Roulette[j];
                }
                cout << endl;
                //Transform roulette into stacked probabilities
                Roulette[0] = Roulette[0]/total;

                for(int j = 1; j < Roulette.size(); ++j)
                    Roulette[j] = Roulette[j-1] + Roulette[j] / total;

                //Select a city from Roulette
                int chosen = 0;
                double r = (double) rand()/RAND_MAX;
                while(Roulette[chosen] < r)
                    chosen++;

                //Add chosen city to
                Colony[ant_i][city_i] = RemainingCities[chosen];
                RemainingCities.erase(RemainingCities.begin() + chosen);
            }
            cout << endl;
            //Save cost of ant_i, for elitist expansion
            costs[ant_i] = pathCost(Colony[ant_i], Map);
        }
        i++;
    }

}

【问题讨论】:

  • 55这个数字有什么意义吗?你也试过使用 gdb 吗?
  • Map[0][i] 应该是Map[i],看我的回答
  • 如果您在 STL 容器上使用基于范围的 for 循环或 for_each(),则您遇到这些错误的可能性较小。

标签: c++ memory segmentation-fault ant-colony


【解决方案1】:

那部分很可疑:

for(int i = 0; i < Map.size(); ++i) //  HERE IT CRASHES AT ANT NUMBER 55
   cout << Map[0][i] << " ";

因为 imap 的大小,但是您将其用作可能的字符串/向量中的索引,因此您可能会使用未定义的行为

也许你想要

for(int i = 0; i < Map.size(); ++i)
   cout << Map[i] << " ";

for(int i = 0; i < Map[0].size(); ++i)
   cout << Map[0][i] << " ";

正如我刚才在评论中所说的,RemainingCities[0] 值 -163172699 在

 cout << "Test: Operation: " << Map.at(Colony.at(ant_i).at(city_i-1)).at(RemainingCities.at(k)) << endl;

so 不是 Map 中的有效索引,但有明显的理由需要查看代码,因此原因可能是 vector 的写入破坏你的记忆元素。

检测我将所有[...] 替换为.at(...) 的位置,并且我遇到的第一个错误是在ACO

 costs.at(ant_i) = pathCost(Colony.at(ant_i), Map);

其中ant_i 的值为 52,而 costs 有 52 个条目,Colony 有 260 个,因此错误涉及 costs

注意ant_i是由循环设置的

 for(int ant_i = 0; ant_i < num_ants; ++ant_i)

在这种情况下,num_ants 的值 260 比 costs 的大小要大得多,它被定义为

 vector<double> costs(cities.size(), 0);

cost只是分配和设置,但从未读取,所以它的目标只是破坏内存。

如果我删除有关它的两行,我不再有错误并且程序正常结束,.at(...) 中没有异常,valgrind 也没有检测到错误。

【讨论】:

  • 正如我所说,地图是一个方阵 (52x52),所以这无关紧要。事实上,即使我尝试像 Map[3][2] 之类的东西,它仍然会出错。
  • @Thiro 无论如何,你所做的循环是错误的,在最好的情况下你没有访问足够的条目
  • ...除了在前面的 54 只蚂蚁中,循环确实可以正常工作(给出正确的输出)并且蚂蚁编号与它无关。我知道这在技术上是不正确的,但是 Map() 和 Map[0]() 的大小是相同的,所以在这种情况下并不重要。反正我改正了,结果是一样的。
  • @Thiro 是的,我得到了完整的代码并查看,我还不知道为什么,但你的问题来自 RemainingCities[0] 值 -163172699 所以不是 Map 中的有效索引。你肯定会破坏你的记忆,但我不知道在哪里
  • @Thiro 在我编译你的代码时有很多警告
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-03
  • 2021-08-04
  • 1970-01-01
  • 2018-01-08
  • 1970-01-01
  • 2020-03-12
相关资源
最近更新 更多