重新排序不相关的指令改变了结果

reordering of unrelated instructions changed the result

本文关键字:指令 改变 结果 不相关 新排序 排序      更新时间:2023-10-16

我有一些代码,其中一些指令是相互独立的(它们不相互影响)。但是当我重新排列它们时,它们的语义(意思)就改变了。就像他们互相影响一样。我不明白为什么。

可疑指令为multigraph->push_back(...)(见代码中的标记)。

我看到两种可能性。要么我不知道它们是如何连接的,要么编译器做错了。

我没有发现任何类似的stackoverflow(也许我使用错误的关键字)。

请告诉我为什么会这样。

您将看到下面的代码。我期望在检查了边[0 3]之后,顶点0的度数为0,即
edge [0 3] → vertex 0 is a leaf -degrees: {0:0} ...

下面是代码(我只提取了重要的部分)。

#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
typedef vector<pair<int, int> >::iterator edgeIt;
vector<pair<int, int> >* some_fun() {
    vector<pair<int, int> >* result = new vector<pair<int, int> >();
    result->push_back(make_pair(0, 3));
    result->push_back(make_pair(1, 2));
    result->push_back(make_pair(1, 4));
    result->push_back(make_pair(2, 5));
    result->push_back(make_pair(3, 5));
    result->push_back(make_pair(3, 8));
    result->push_back(make_pair(5, 6));
    result->push_back(make_pair(6, 7));
    return result;
}
const int n = 9;
int degree[n];
int main() {
        vector<pair<int, int> >* multigraph = some_fun();
        sort(multigraph->begin(), multigraph->end());
        /// vertices' degrees
        int degree[n];
        for (int i=0 ; i<n ; degree[i++]=0);
        for (edgeIt it=multigraph->begin() ; it!=multigraph->end() ; it++){
            degree[it->first]++;
            degree[it->second]++;
        }
        cerr << "   degrees: ";
        for (int i=0 ; i<n ; i++)
            cerr << "{" << i << ":" << degree[i] << "} ";
        cerr << endl;
        /// double edges for leaves
        vector<int> leaves;
        int mstSize = multigraph->size();
        for (int i=0 ; i<mstSize ; i++) {
            pair<int, int>* el = &(*multigraph)[i];
            cerr << "   edge [" << el->first << " " << el->second << "] n";
            if (degree[el->first]==1) {
                cerr << "     → vertex " << el->first << " is a leaf n";
                // here it will not work
                // multigraph->push_back(make_pair(el->first, el->second));
                degree[el->first]=0;
                degree[el->second]++;
                // but here it's OK
                multigraph->push_back(make_pair(el->first, el->second));
                leaves.push_back(el->first);
            }
            else if (degree[el->second]==1) {
                cerr << "     →→ vertex " << el->second << " is a leaf n";
                degree[el->first]++;
                degree[el->second]=0;
                multigraph->push_back(make_pair(el->first, el->second));
                leaves.push_back(el->second);
            }
            cerr << "t      -degrees: ";
            for (int i=0 ; i<n ; i++)
                cerr << "{" << i << ":" << degree[i] << "} ";
            cerr << endl;
        }
        cerr << "    *leaves: ";
        for (int i=0 ; i<leaves.size() ; ++i)
            cerr << leaves[i] << " ";
        cerr << endl;
        delete multigraph;
    return 0;
}

我找到了罪魁祸首。
如果向量变大会怎样?它可以重新分配它的内容,这样el将不再指向向量的第i个元素,它将指向内存中某个意义未知的位置。

指令

pair<int, int>* el = &(*multigraph)[i];

是危险的。它接受vector容器中元素的地址。
push_back指令触发重新分配,因此在之后调用el->first 不再正确。
对矢量进行更改之前,从el 下读取值可以修复此问题。