这是一个创建Clustering对象并按值返回它的方法。

Clustering ClusteringGenerator::makeOneClustering(Graph& G) {
    int64_t n = G.numberOfNodes();
    Clustering zeta(n);
    cluster one = zeta.addCluster();
    for (node v = G.firstNode(); v <= n; ++v) {
        zeta.addToCluster(one, v);
    }
    return zeta;
}

此循环多次调用该方法,并将指向返回值的指针添加到 vector 。
    int z = 3
    for (int i = 0; i < z; ++i) {
        // FIXME: why is zeta the same each iteration?
        Clustering zeta = clusterGen.makeOneClustering(G);
        DEBUG(&zeta);
        clusterings.push_back(&zeta);
    }

DEBUG语句的输出是
0x7fff4ff894d0
0x7fff4ff894d0
0x7fff4ff894d0

因此,这意味着&zeta在每次迭代中都是相同的指针。为什么?
如何获得所需的结果(每次迭代创建一个Clustering对象并将其记住在 vector 中)?

最佳答案

因为zeta是一个自动变量(循环中的一个变量,另一个也是局部变量,但是ClusteringGenerator::makeOneClustering本身没有任何错误),一旦当前循环迭代结束(和zeta的变量就不再存在)析构函数已被调用)。因此,编译器可以自由地将其底层存储用于其他变量(例如,下一次循环迭代中的zeta),并且如果不这样做,将非常愚蠢。

同样,您的代码也容易出错,因为它会将局部变量的地址存储在容器中,尽管如上所述,该变量在push_back之后不再存在。

为了解决这个问题,要么使用std::vector<Clustering>并按值放入这些东西,要么,如果您确实需要存储指针(也许是因为您不使用C++ 11的移动语义/从中获利,并且担心复制开销) ),然后动态分配这些循环对象,以防止它们被自动破坏。但是在后一种情况下(考虑到Clustering似乎可以很好地复制,无论如何使用,您都应该彻底考虑一下),而应该使用某种智能指针来照顾对动态分配对象的适当破坏。

10-07 22:33