我有两节课。出于说明目的,我使用菜单和菜单项的想法
class Menu {
public:
...
RemoveItem(Item* item) {
// Remove appropriate item from menu_items vector
};
private:
std::vector<std::shared_ptr<Item>> menu_items;
}
class Item {
public:
Item(Menu* owner) : menu{owner} {}
~Item() { RemoveThisMenuItem() }
void RemoveThisMenuItem() {
for (const auto& ingredient : ingredients) {
ingredient.SetNecessary(false);
}
menu.RemoveItem(this);
}
...
private:
Menu* menu;
std::vector<Ingredients*> ingredients;
...
}
基本上,我有一个类Item
所拥有的类Menu
(并且可能在其他地方用shared_ptr
引用了)。现在,我要删除一个项目。删除Item后,它需要首先执行其他一些功能(例如将所有成分标记为不必要),然后将其从Menu
中删除。
现在实现方式,我们要删除项目时会有一个奇怪的循环,因为调用Item::RemoveThisMenuItem()
会调用Menu
中的函数,该函数会删除指向Item
的智能指针,它调用析构函数~Item()
,然后调用析构函数Item::RemoveThisMenuItem()
。解决此问题的最佳方法是什么?
答案 0 :(得分:1)
再复制拥有该物品的shared_ptr
,并在其超出范围时将其销毁。
即而不是:
menu_items[n]->RemoveThisMenuItem();
这样做:
{
auto owner = menu_items[n];
owner->RemoveThisMenuItem();
}
现在,当RemoveThisMenuItem()
从向量中删除元素时,它不是共享Item
所有权的最后一个对象,因此直到owner
消失后它才被销毁范围。
答案 1 :(得分:0)
我将方法void RemoveItem(Item* item)
更改为std::shared_ptr<Item> RemoveItem(Item* item)
并以一种方式实现它,即将相应的item-shared_ptr从向量中移出/复制并返回;如果该项已被删除,则返回一个空的共享ptr,以避免无休止的递归。这样,您可以防止RemoveItem
过时地删除Item对象(以防该对象的最后一个shared_ptr被破坏)并将该主题委托给RemoveItem的调用者。然后,调用者可以决定是否保留这样的shared_pointer(以及相应的对象)。
例如:
void RemoveThisMenuItem() {
for (const auto& ingredient : ingredients) {
ingredient.SetNecessary(false);
}
auto ptr = menu.RemoveItem(this);
// at that point, "this" will have not been destroyed;
// when the method is left, however, ptr will be destroyed and the destructor will be called;
}