对于一个项目,我有一个对象列表(在我的示例代码中是一个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
应该具有对新的Garden
的引用,而不仅仅是复制旧的引用。
使用新的C++ 11功能,实际上可以避免复制和由此产生的整个问题:
gardenList.emplace_back(1);
现在,the
Garden
in the list is created in-place,将不执行任何复制。但是,即使以这种方式解决问题,您仍然应该使用
Garden
来解决潜在的设计问题。关于c++ - C++隐式拷贝* this与std::list,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24307077/