What is the correct way to remove boost :: shared_ptr from the list?

I have a std::list from boost::shared_ptr<T> and I want to remove an element from it, but I only have a pointer of type T * that corresponds to one of the elements in the list.

However, I cannot use myList.remove( tPtr ) I assume, because shared_ptr does not implement == for its type of template argument.

I immediately thought about trying myList.remove( shared_ptr<T>(tPtr) ) , which is syntactically correct, but it will exit double deletion, since the temporary shared_ptr has a separate use_count.

 std::list< boost::shared_ptr<T> > myList; T* tThisPtr = new T(); // This is wrong; only done for example code. // stand-in for actual code in T using // T actual "this" pointer from within T { boost::shared_ptr<T> toAdd( tThisPtr ); // typically would be new T() myList.push_back( toAdd ); } { //T has pointer to myList so that upon a certain action, // it will remove itself romt the list //myList.remove( tThisPtr); //doesn't compile myList.remove( boost::shared_ptr<T>(tThisPtr) ); // compiles, but causes // double delete } 

The only options I see for the rest are using std :: find with a custom comparison or cycling around the list and searching for it yourself, but it seems like there should be a better way.

Am I missing something obvious or is it too substandard use to remove the clean / regular way?

+4
source share
4 answers

enable_shared_from_this may help with your problem, but this will require the types you use in the list:

If the type activates this function, you can get a shared pointer from the object itself by calling shared_from_this() .

+3
source

You are right, we cannot directly compare pointers. But there is remove_if , and we can specify our own predicate. Decision:

 template <typename T> struct ptr_contains_predicate { ptr_contains_predicate(T* pPtr) : mPtr(pPtr) {} template <typename P> bool operator()(const p& pPtr) const { return pPtr.get() == mPtr; } T* mPtr; }; template <typename T> ptr_contains_predicate<T> ptr_contains(T* pPtr) { return ptr_contains_predicate<T>(pPtr); } 

Just keep the above predicate in the header somewhere, and you can use it wherever you want.

 myList.remove_if(ptr_contains(tThisPtr)); 

The best solution is to never lose shared_ptr in the first place, so we can just use remove , but it's harmless anyway.

+5
source

std :: list remove_if is what you need:

Define a predicate

 template <typename T> struct shared_equals_raw { shared_equals_raw(T* raw) :_raw(raw) {} bool operator()(const boost::shared_ptr<T>& ptr) const { return (ptr.get()==_raw); } private: T*const _raw; }; 

then you can call

 myList.remove_if(shared_equals_raw(tThisPtr)); 

to remove the list of nodes that have shared_ptrs in tThisPtr.

(Untested, so maybe some syntax things need to be fixed).

Michael Barr advises enabling enable_shared_from_this this is good; it would be better to avoid raw tThisPtr playing at all.

+4
source

Can I use a generic pointer to delete it?

 std::list< boost::shared_ptr<T> > myList; boost::shared_ptr<T> tThisPtr = new T(); { myList.push_back(tThisPtr); } { myList.remove(tThisPtr); } 
0
source

Source: https://habr.com/ru/post/1306317/


All Articles