Prevent object owned by shared_ptr from being deleted while member function executes
up vote
-1
down vote
favorite
I have two classes. For illustrative purposes, I'm using the idea of a menu and menu items
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) : menuowner
~Item() RemoveThisMenuItem()
void RemoveThisMenuItem()
for (const auto& ingredient : ingredients)
ingredient.SetNecessary(false);
menu.RemoveItem(this);
...
private:
Menu* menu;
std::vector<Ingredients*> ingredients;
...
Essentially, I have a class Item that is owned by a class Menu (and possibly referenced elsewhere with shared_ptrs). Now, I want to remove an Item. When Item is deleted, it needs to perform some other functions first (like marking all of the ingredients unnecessary) and then remove it from the Menu.
The way things are implemented now, there's a strange loop when we want to remove the item, since calling Item::RemoveThisMenuItem() calls a function in Menu that removes the smart pointer to the Item, which calls the destructor ~Item(), which then calls Item::RemoveThisMenuItem(). What's the best way to get around this?
c++ c++11 shared-ptr
add a comment |
up vote
-1
down vote
favorite
I have two classes. For illustrative purposes, I'm using the idea of a menu and menu items
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) : menuowner
~Item() RemoveThisMenuItem()
void RemoveThisMenuItem()
for (const auto& ingredient : ingredients)
ingredient.SetNecessary(false);
menu.RemoveItem(this);
...
private:
Menu* menu;
std::vector<Ingredients*> ingredients;
...
Essentially, I have a class Item that is owned by a class Menu (and possibly referenced elsewhere with shared_ptrs). Now, I want to remove an Item. When Item is deleted, it needs to perform some other functions first (like marking all of the ingredients unnecessary) and then remove it from the Menu.
The way things are implemented now, there's a strange loop when we want to remove the item, since calling Item::RemoveThisMenuItem() calls a function in Menu that removes the smart pointer to the Item, which calls the destructor ~Item(), which then calls Item::RemoveThisMenuItem(). What's the best way to get around this?
c++ c++11 shared-ptr
4
IfItem::~Itemis executing, then the item must have already been removed from the menu. Otherwise there would still be ashared_ptr<Item>for it and it would not have been destroyed yet. If you are destroying anItemwhich there is still ashared_ptr<Item>to it you have a design error elsewhere in your code.
– François Andrieux
Nov 8 at 18:18
1
Please clarify your question with a complete example. It's unclear how you can be trying to remove something from the vector while it is being destroyed.
– Jonathan Wakely
Nov 8 at 19:11
add a comment |
up vote
-1
down vote
favorite
up vote
-1
down vote
favorite
I have two classes. For illustrative purposes, I'm using the idea of a menu and menu items
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) : menuowner
~Item() RemoveThisMenuItem()
void RemoveThisMenuItem()
for (const auto& ingredient : ingredients)
ingredient.SetNecessary(false);
menu.RemoveItem(this);
...
private:
Menu* menu;
std::vector<Ingredients*> ingredients;
...
Essentially, I have a class Item that is owned by a class Menu (and possibly referenced elsewhere with shared_ptrs). Now, I want to remove an Item. When Item is deleted, it needs to perform some other functions first (like marking all of the ingredients unnecessary) and then remove it from the Menu.
The way things are implemented now, there's a strange loop when we want to remove the item, since calling Item::RemoveThisMenuItem() calls a function in Menu that removes the smart pointer to the Item, which calls the destructor ~Item(), which then calls Item::RemoveThisMenuItem(). What's the best way to get around this?
c++ c++11 shared-ptr
I have two classes. For illustrative purposes, I'm using the idea of a menu and menu items
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) : menuowner
~Item() RemoveThisMenuItem()
void RemoveThisMenuItem()
for (const auto& ingredient : ingredients)
ingredient.SetNecessary(false);
menu.RemoveItem(this);
...
private:
Menu* menu;
std::vector<Ingredients*> ingredients;
...
Essentially, I have a class Item that is owned by a class Menu (and possibly referenced elsewhere with shared_ptrs). Now, I want to remove an Item. When Item is deleted, it needs to perform some other functions first (like marking all of the ingredients unnecessary) and then remove it from the Menu.
The way things are implemented now, there's a strange loop when we want to remove the item, since calling Item::RemoveThisMenuItem() calls a function in Menu that removes the smart pointer to the Item, which calls the destructor ~Item(), which then calls Item::RemoveThisMenuItem(). What's the best way to get around this?
c++ c++11 shared-ptr
c++ c++11 shared-ptr
asked Nov 8 at 18:16
quantumwell
92
92
4
IfItem::~Itemis executing, then the item must have already been removed from the menu. Otherwise there would still be ashared_ptr<Item>for it and it would not have been destroyed yet. If you are destroying anItemwhich there is still ashared_ptr<Item>to it you have a design error elsewhere in your code.
– François Andrieux
Nov 8 at 18:18
1
Please clarify your question with a complete example. It's unclear how you can be trying to remove something from the vector while it is being destroyed.
– Jonathan Wakely
Nov 8 at 19:11
add a comment |
4
IfItem::~Itemis executing, then the item must have already been removed from the menu. Otherwise there would still be ashared_ptr<Item>for it and it would not have been destroyed yet. If you are destroying anItemwhich there is still ashared_ptr<Item>to it you have a design error elsewhere in your code.
– François Andrieux
Nov 8 at 18:18
1
Please clarify your question with a complete example. It's unclear how you can be trying to remove something from the vector while it is being destroyed.
– Jonathan Wakely
Nov 8 at 19:11
4
4
If
Item::~Item is executing, then the item must have already been removed from the menu. Otherwise there would still be a shared_ptr<Item> for it and it would not have been destroyed yet. If you are destroying an Item which there is still a shared_ptr<Item> to it you have a design error elsewhere in your code.– François Andrieux
Nov 8 at 18:18
If
Item::~Item is executing, then the item must have already been removed from the menu. Otherwise there would still be a shared_ptr<Item> for it and it would not have been destroyed yet. If you are destroying an Item which there is still a shared_ptr<Item> to it you have a design error elsewhere in your code.– François Andrieux
Nov 8 at 18:18
1
1
Please clarify your question with a complete example. It's unclear how you can be trying to remove something from the vector while it is being destroyed.
– Jonathan Wakely
Nov 8 at 19:11
Please clarify your question with a complete example. It's unclear how you can be trying to remove something from the vector while it is being destroyed.
– Jonathan Wakely
Nov 8 at 19:11
add a comment |
2 Answers
2
active
oldest
votes
up vote
1
down vote
Make another copy of the shared_ptr which owns the item, and will destroy it when it goes out of scope.
i.e. instead of doing:
menu_items[n]->RemoveThisMenuItem();
do:
auto owner = menu_items[n];
owner->RemoveThisMenuItem();
Now when RemoveThisMenuItem() erases the element from the vector it isn't the last object that shares ownership of the Item, and so it won't be destroyed until owner goes out of scope.
2
RemoveThisMenuItemis being called from the context of the destructor. The destructor is already running. If there was astd::shared_ptrto copy, the destructor would not be running in the first place.
– François Andrieux
Nov 8 at 18:23
Ugh, I didn't see that. Yes, something is wrong with the design then.
– Jonathan Wakely
Nov 8 at 19:08
add a comment |
up vote
0
down vote
I'd change method void RemoveItem(Item* item) to std::shared_ptr<Item> RemoveItem(Item* item) and implement it in a way that it moves/copies the respective item-shared_ptr out of the vector and returns it; if the item has already been removed, return an empty shared ptr to avoid endless recursion. This way, you prevent RemoveItem to ocassionally delete the Item-object (in case the last shared_ptr of it was destroyed) and delegate the topic to the caller of RemoveItem. The caller can then decide if to keep such a shared_pointer (and thereby the corresponding object) alive or not.
For example:
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;
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
Make another copy of the shared_ptr which owns the item, and will destroy it when it goes out of scope.
i.e. instead of doing:
menu_items[n]->RemoveThisMenuItem();
do:
auto owner = menu_items[n];
owner->RemoveThisMenuItem();
Now when RemoveThisMenuItem() erases the element from the vector it isn't the last object that shares ownership of the Item, and so it won't be destroyed until owner goes out of scope.
2
RemoveThisMenuItemis being called from the context of the destructor. The destructor is already running. If there was astd::shared_ptrto copy, the destructor would not be running in the first place.
– François Andrieux
Nov 8 at 18:23
Ugh, I didn't see that. Yes, something is wrong with the design then.
– Jonathan Wakely
Nov 8 at 19:08
add a comment |
up vote
1
down vote
Make another copy of the shared_ptr which owns the item, and will destroy it when it goes out of scope.
i.e. instead of doing:
menu_items[n]->RemoveThisMenuItem();
do:
auto owner = menu_items[n];
owner->RemoveThisMenuItem();
Now when RemoveThisMenuItem() erases the element from the vector it isn't the last object that shares ownership of the Item, and so it won't be destroyed until owner goes out of scope.
2
RemoveThisMenuItemis being called from the context of the destructor. The destructor is already running. If there was astd::shared_ptrto copy, the destructor would not be running in the first place.
– François Andrieux
Nov 8 at 18:23
Ugh, I didn't see that. Yes, something is wrong with the design then.
– Jonathan Wakely
Nov 8 at 19:08
add a comment |
up vote
1
down vote
up vote
1
down vote
Make another copy of the shared_ptr which owns the item, and will destroy it when it goes out of scope.
i.e. instead of doing:
menu_items[n]->RemoveThisMenuItem();
do:
auto owner = menu_items[n];
owner->RemoveThisMenuItem();
Now when RemoveThisMenuItem() erases the element from the vector it isn't the last object that shares ownership of the Item, and so it won't be destroyed until owner goes out of scope.
Make another copy of the shared_ptr which owns the item, and will destroy it when it goes out of scope.
i.e. instead of doing:
menu_items[n]->RemoveThisMenuItem();
do:
auto owner = menu_items[n];
owner->RemoveThisMenuItem();
Now when RemoveThisMenuItem() erases the element from the vector it isn't the last object that shares ownership of the Item, and so it won't be destroyed until owner goes out of scope.
answered Nov 8 at 18:21
Jonathan Wakely
129k15236399
129k15236399
2
RemoveThisMenuItemis being called from the context of the destructor. The destructor is already running. If there was astd::shared_ptrto copy, the destructor would not be running in the first place.
– François Andrieux
Nov 8 at 18:23
Ugh, I didn't see that. Yes, something is wrong with the design then.
– Jonathan Wakely
Nov 8 at 19:08
add a comment |
2
RemoveThisMenuItemis being called from the context of the destructor. The destructor is already running. If there was astd::shared_ptrto copy, the destructor would not be running in the first place.
– François Andrieux
Nov 8 at 18:23
Ugh, I didn't see that. Yes, something is wrong with the design then.
– Jonathan Wakely
Nov 8 at 19:08
2
2
RemoveThisMenuItem is being called from the context of the destructor. The destructor is already running. If there was a std::shared_ptr to copy, the destructor would not be running in the first place.– François Andrieux
Nov 8 at 18:23
RemoveThisMenuItem is being called from the context of the destructor. The destructor is already running. If there was a std::shared_ptr to copy, the destructor would not be running in the first place.– François Andrieux
Nov 8 at 18:23
Ugh, I didn't see that. Yes, something is wrong with the design then.
– Jonathan Wakely
Nov 8 at 19:08
Ugh, I didn't see that. Yes, something is wrong with the design then.
– Jonathan Wakely
Nov 8 at 19:08
add a comment |
up vote
0
down vote
I'd change method void RemoveItem(Item* item) to std::shared_ptr<Item> RemoveItem(Item* item) and implement it in a way that it moves/copies the respective item-shared_ptr out of the vector and returns it; if the item has already been removed, return an empty shared ptr to avoid endless recursion. This way, you prevent RemoveItem to ocassionally delete the Item-object (in case the last shared_ptr of it was destroyed) and delegate the topic to the caller of RemoveItem. The caller can then decide if to keep such a shared_pointer (and thereby the corresponding object) alive or not.
For example:
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;
add a comment |
up vote
0
down vote
I'd change method void RemoveItem(Item* item) to std::shared_ptr<Item> RemoveItem(Item* item) and implement it in a way that it moves/copies the respective item-shared_ptr out of the vector and returns it; if the item has already been removed, return an empty shared ptr to avoid endless recursion. This way, you prevent RemoveItem to ocassionally delete the Item-object (in case the last shared_ptr of it was destroyed) and delegate the topic to the caller of RemoveItem. The caller can then decide if to keep such a shared_pointer (and thereby the corresponding object) alive or not.
For example:
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;
add a comment |
up vote
0
down vote
up vote
0
down vote
I'd change method void RemoveItem(Item* item) to std::shared_ptr<Item> RemoveItem(Item* item) and implement it in a way that it moves/copies the respective item-shared_ptr out of the vector and returns it; if the item has already been removed, return an empty shared ptr to avoid endless recursion. This way, you prevent RemoveItem to ocassionally delete the Item-object (in case the last shared_ptr of it was destroyed) and delegate the topic to the caller of RemoveItem. The caller can then decide if to keep such a shared_pointer (and thereby the corresponding object) alive or not.
For example:
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;
I'd change method void RemoveItem(Item* item) to std::shared_ptr<Item> RemoveItem(Item* item) and implement it in a way that it moves/copies the respective item-shared_ptr out of the vector and returns it; if the item has already been removed, return an empty shared ptr to avoid endless recursion. This way, you prevent RemoveItem to ocassionally delete the Item-object (in case the last shared_ptr of it was destroyed) and delegate the topic to the caller of RemoveItem. The caller can then decide if to keep such a shared_pointer (and thereby the corresponding object) alive or not.
For example:
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;
edited Nov 8 at 19:09
François Andrieux
14.8k32345
14.8k32345
answered Nov 8 at 18:31
Stephan Lechner
24.3k21738
24.3k21738
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53213828%2fprevent-object-owned-by-shared-ptr-from-being-deleted-while-member-function-exec%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
4
If
Item::~Itemis executing, then the item must have already been removed from the menu. Otherwise there would still be ashared_ptr<Item>for it and it would not have been destroyed yet. If you are destroying anItemwhich there is still ashared_ptr<Item>to it you have a design error elsewhere in your code.– François Andrieux
Nov 8 at 18:18
1
Please clarify your question with a complete example. It's unclear how you can be trying to remove something from the vector while it is being destroyed.
– Jonathan Wakely
Nov 8 at 19:11