2

Suppose I have a Mutexed queue called MQueue:

#include <deque> template< typename T > class MQueue { public: T* pop() { lock(); T* ptr = nullptr; // get it out of m_dq... unlock(); return ptr; } // push, etc... and other methods private: std::deque<T*> m_dq; }; 

The following instantiation has been tested and works fine:

MQueue< int > my_simple_mq;

What kinds of modifications do I need to make to MQueue to ensure that

MQueue< std::unique_ptr< int > > my_smart_mq; 

will behave properly? I have attempted to browse the code to std::vector<> for reference, but it's difficult for me to discern which parts of the implementation are pertinent for the proper working of smart pointers. Any references or links would be greatly appreciated.

7
  • 1
    Impossible to tell without those details. Why do you store T*, and how? Do you want T = unique_ptr<U>, or do you want to replace T* by unique_ptr<T>? Commented Dec 1, 2011 at 13:53
  • I am totally open to changing the T* internal implementation to something else. Currently, the MQueue instance owns all of its entries so calls delete on them upon destruction. That means, if I just want callers to work, I could just replace the internal implementation with unique_ptr<T> in the right place. However, I thought it would be nice to write a more generic MQueue<T> which allows the user to decide if he wants the container to own the the items or not - in other words, make MQueue behave more like STL containers rather than force taking ownership of items (current implementation). Commented Dec 1, 2011 at 14:00
  • Hm, I'm not sure just now if you got the right idea of how standard containers work (e.g. the deque already owns its contents), but maybe you'll find this article by Herb Sutter interesting. Commented Dec 1, 2011 at 14:15
  • Why aren't you just storing and returning the things by-value? Commented Dec 1, 2011 at 14:19
  • 1
    @kfmfe04 move semantics are your friend :) That's how you prevent expensive copies. Commented Dec 1, 2011 at 14:39

1 Answer 1

3

If you just want to replace the T* with unique_ptr<T>, then it would look something like:

template< typename T > class MQueue { public: std::unique_ptr<T> pop() { lock(); std::unique_ptr<T> ptr = std::move(m_dq.back()); m_dq.pop_back(); unlock(); return ptr; } // push, etc... and other methods private: std::deque<std::unique_ptr<T>> m_dq; }; 

But on reading your comment in the question, it is now not clear that is what you're asking. If you want your unqiue_ptr to sometimes own the pointer and sometimes not, you can write a custom deleter which holds a flag stating whether or not it should delete the pointer. Clients of unique_ptr can access a reference to the deleter (via the get_deleter() accessor) to inspect/change that flag.

Here's example (untested) code that shows how that might look:

template <class T> class my_deleter { bool owns_; public: explicit my_deleter(bool owns) : owns_(owns) {} bool owns() const {return owns_;} void set_owns(bool owns) {owns_ = owns;} void operator()(T* p) {if (owns_) delete p;} }; template< typename T > class MQueue { public: typedef std::unique_ptr<T, my_deleter<T>> Ptr; Ptr pop() { lock(); Ptr ptr = std::move(m_dq.back()); m_dq.pop_back(); unlock(); return ptr; } // push, etc... and other methods private: std::deque<Ptr> m_dq; }; 
Sign up to request clarification or add additional context in comments.

2 Comments

ty - actually that get_deleter() hint is what I am looking for (I know how to use unique_ptr<> inside MQueue - rather, I'm trying to figure out how to allow the user to pass in/not pass in unique_ptr<> as a parameter on instantiation).
If it may or may not own it std::shared_ptr would make more sense

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.