C ++ *此与std :: list的隐式副本

桑切斯

对于一个项目,我有一个对象列表(在我的示例代码中是一个Garden)。每个花园都包含一个植物,该植物对其所在的花园有一个引用。这在创建单个花园时效果很好,但是当我创建花园对象的std :: list时,突然在我不知道的地方创建了一个副本,但我不知道如何解决。对象如下:

struct Garden; //Forward declaration
struct Plant {
    Plant(Garden & myGarden) : theGarden(myGarden) { }; //Constructor
    Garden & theGarden; //reference to garden this Plant is in
};
struct Garden {
    Garden(int size) :  thePlant(*this), size(size) { }; //Constructor
    Plant thePlant; //Plant contained in this Garden
    int size;       //Size of this garden
};

到目前为止,一切都很好。现在,我可以创建一个独立的Garden或将其放在列表中。预期的行为是,如果我更改了'size'变量,它将在所有地方(也在)中都被更改theGarden但是,在列表中,只能在“原始”中更改它Garden,而在参考中则不会更改theGarden

int main() {
    //Works
    Garden oneGarden(1);
    std::cout << "Expected: 1 1, result: "
            << oneGarden.size << " "
            << oneGarden.thePlant.theGarden.size << std::endl;
    oneGarden.size = 2;
    std::cout << "Expected: 2 2, result: "
            << oneGarden.size << " "
            << oneGarden.thePlant.theGarden.size << std::endl;

    //Does not work!
    std::list<Garden> gardenList;
    gardenList.push_back(Garden(1));
    std::cout << "Expected: 1 1, result: "
            << gardenList.front().size << " "
            << gardenList.front().thePlant.theGarden.size << std::endl;

    gardenList.front().size = 2;
    std::cout << "Expected: 2 2, result: "
                << gardenList.front().size << " "
                << gardenList.front().thePlant.theGarden.size << std::endl;

    return 0;
}

最终输出如下:

Expected: 1 1, result: 1 1
Expected: 2 2, result: 2 2
Expected: 1 1, result: 1 1
Expected: 2 2, result: 2 1
轨道轻度竞赛

标准容器拥有它们包含的元素。这意味着在插入每个元素时,它们是由每个元素组成的。

Garden复制的文件时,将使用默认的复制构造函数,并且该Plant成员也将默认复制。但是,这意味着新的Plant包含了对 的引用Garden

在这种情况下,那个旧的Garden只是暂时的,gardenList.push_back(Garden(1))所以它不仅不正确Garden,而且Garden不再存在。简而言之,您正在通过一个悬空的引用(具有不确定的行为)读取该大小,并[很不幸]足够幸运地看到其背后的旧值。

您应该编写一个复制构造函数,以各种方式Garden复制它Plant除了新的Plant应该具有对new的引用Garden,而不仅仅是复制旧的引用。

使用C ++ 11的新功能实际上可以避免复制和由此产生的整个问题:

gardenList.emplace_back(1);

现在,Garden列表中的就地创建,并且将不会进行拷贝。

但是,即使以这种方式解决问题,您仍然应该使用解决潜在的设计问题Garden

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章