Как мне создать контейнер, который будет правильно работать с std :: unique_ptr в качестве параметра шаблона? - PullRequest
2 голосов
/ 01 декабря 2011

Предположим, у меня есть очередь Mutexed с именем 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;
};

Следующие экземпляры были протестированы и отлично работают:

MQueue< int > my_simple_mq;

Какие изменения мне нужно внести в MQueue, чтобы

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

будет вести себя правильно? Я попытался просмотреть код в std :: vector <> для справки, но мне трудно определить, какие части реализации имеют отношение к правильной работе интеллектуальных указателей. Любые ссылки или ссылки будут с благодарностью.

1 Ответ

3 голосов
/ 01 декабря 2011

Если вы просто хотите заменить T* на unique_ptr<T>, то это будет выглядеть примерно так:

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;
};

Но, прочитав ваш комментарий в вопросе, теперь не ясно, о чем вы спрашиваете. Если вы хотите, чтобы ваш unqiue_ptr иногда владел указателем, а иногда нет, вы можете написать пользовательский удалитель, который содержит флаг, указывающий, должен ли он удалить указатель. Клиенты unique_ptr могут получить доступ к ссылке на средство удаления (через средство доступа get_deleter()), чтобы проверить / изменить этот флаг.

Вот пример (непроверенный) кода, который показывает, как это может выглядеть:

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;
};
...