I have a class "story", which must be stored in various collections. The bottom line is that I use pointers, i.e.

class Story { ... } class Compilation { ... vector<Story*> stories; ... } 

It is necessary to change the information about the stories. Everything is clear here, since we store pointers, everything will change in parallel. Removal from a specific collection is also clear. But if it turns out that this collection is the last one, where our story is stored, how to delete it without a memory leak? If we want to delete the story forever, then how to remove it from all collections at once?

To keep collections inside the story is also not an option, since it is necessary to arrange a search on collections, the number of stories in them, etc.

  • Alternatively, use the object reference count. When a story is added to a collection or deleted, it is increased or decreased by 1. When it is 0 (the collection was last), the story can be deleted. By the way, this is how COM technology works in Windows. - Streletz
  • @Streletz and when removing from all collections to do a complete bust? - GFalls
  • For what purpose??? - Streletz
  • @Streletz for example, we need to delete the story once and for all from everywhere - GFalls
  • Use vector<shared_ptr<Story>> stories . (She has a <s> neon </ s> reference count.) - VladD

2 answers 2

You need to use shared_ptr instead of a raw pointer. In this case, your object will be deleted only when the last pointer to it dies.

Here is a small example of working with it :

 #include <iostream> #include <vector> #include <memory> using namespace std; class Story { int n; public: Story(int n): n(n) { cout << "story #" << n << " created" << endl; } ~Story() { cout << "story #" << n << " destroyed" << endl; } }; int main() { vector<shared_ptr<Story>> list1, list2; cout << "creating #1 and adding to first list" << endl; list1.emplace_back(make_shared<Story>(1)); cout << "copying #1 to second list" << endl; list2.push_back(list1[0]); cout << "creating #2" << endl; auto story2 = make_shared<Story>(2); cout << "adding #2 to the second list" << endl; list2.push_back(story2); cout << "removing first ptr to story #2" << endl; story2 = nullptr; cout << "removing second ptr to story #2, now it will be destroyed" << endl; list2.resize(1); cout << "clearing first list" << endl; list1.clear(); cout << "clearing second list, now story #1 will be destroyed" << endl; list2.clear(); cout << "done" << endl; } 

Conclusion:

creating # 1 and adding to first list
story # 1 created
copying # 1 to second list
creating # 2
story # 2 created
Adding # 2 to the second list
removing first ptr to story # 2
removing second ptr to story # 2, now it will be destroyed
story # 2 destroyed
clearing first list
clearing second list, now story # 1 will be destroyed
story # 1 destroyed
done


As @ixSci correctly suggests in the comments, you can delete the item completely in all lists if you accept a slightly different design. We divide lists into those owning their own elements (these lists will contain shared_ptr ), and non-owning (these lists will contain weak_ptr , non- weak_ptr pointer). Then when all strong links ( shared_ptr ) to an object die, weak weak_ptr ( weak_ptr ) will also become invalid.

This is made out as follows :

 #include <iostream> #include <vector> #include <memory> #include <algorithm> using namespace std; class Story { int n; public: Story(int n): n(n) { cout << "story #" << n << " created" << endl; } ~Story() { cout << "story #" << n << " destroyed" << endl; } void print() { cout << "story #" << n << " reporting" << endl; } }; int main() { vector<shared_ptr<Story>> main_list; vector<weak_ptr<Story>> aux_list; cout << "creating and adding to owning list" << endl; main_list.emplace_back(make_shared<Story>(1)); main_list.emplace_back(make_shared<Story>(2)); cout << "copying to non-owning list" << endl; aux_list.push_back(main_list[0]); aux_list.push_back(main_list[1]); cout << "removing #2" << endl; main_list.resize(1); for (auto& weakptr : aux_list) { if (auto strongptr = weakptr.lock()) strongptr->print(); else cout << "(deleted entry)" << endl; } cout << "cleaning non-owning list" << endl; aux_list.erase( remove_if(begin(aux_list), end(aux_list), [](auto wp) { return wp.expired(); }), end(aux_list)); for (auto& weakptr : aux_list) { if (auto strongptr = weakptr.lock()) strongptr->print(); else cout << "(cannot happen)" << endl; } cout << "done" << endl; } 

Conclusion:

creating and adding to owning list
story # 1 created
story # 2 created
copying to non-owning list
removing # 2
story # 2 destroyed
story # 1 reporting
(deleted entry)
cleaning non-owning list
story # 1 reporting
done
story # 1 destroyed

  • One question, what if I want to remove a specific story from everywhere at once? - GFalls
  • @GFalls: Because each shared_ptr makes a "contribution" to the life of an object, you will have to destroy (remove from the array, zero out, anything) all shared_ptr 's on it. Now add to the example. - VladD
  • @GFalls: Added. - VladD
  • one
    @GFalls: You’ll have to look up the value by list and delete. Something like this: ideone.com/8qgZ3e . Notice that with a raw pointer you just can't just delete an object, as long as there are links to it in vectors (obviously, why?) - VladD
  • one
    @GFalls: Updated the answer. - VladD

Use the smart pointer shared_ptr<Story> - this is exactly what you need.