如何创建一个可以将 std::unique_ptr 作为模板参数正常工作的容器?

Posted

技术标签:

【中文标题】如何创建一个可以将 std::unique_ptr 作为模板参数正常工作的容器?【英文标题】:How do I create a container that will work properly with std::unique_ptr as a template parameter? 【发布时间】:2011-12-01 13:44:31 【问题描述】:

假设我有一个名为 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&lt; int &gt; my_simple_mq;

我需要对 MQueue 进行哪些修改以确保

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

行为会正常吗?我试图将代码浏览到 std::vector 以供参考,但我很难辨别实现的哪些部分与智能指针的正常工作相关。任何参考或链接将不胜感激。

【问题讨论】:

没有这些细节就无法判断。为什么要存储T*,以及如何存储?您想要T = unique_ptr&lt;U&gt;,还是想要替换 T*unique_ptr&lt;T&gt; 我完全愿意将 T* 内部实现更改为其他内容。目前,MQueue 实例拥有它的所有条目,因此在销毁时对它们调用 delete。这意味着,如果我只想让调用者工作,我可以在正确的位置用 unique_ptr 替换内部实现。但是,我认为编写一个更通用的 MQueue 会很好,它允许用户决定他是否希望容器拥有这些项目 - 换句话说,使 MQueue 的行为更像 STL 容器而不是强制取得项目的所有权(当前实施)。 嗯,我现在不确定你是否对标准容器的工作方式有正确的认识(例如,deque 已经拥有它的内容),但也许你'会觉得this article by Herb Sutter很有趣。 你为什么不按值存储和返回东西? @kfmfe04 移动语义是你的朋友 :) 这就是你防止昂贵复制的方法。 【参考方案1】:

如果您只想用unique_ptr&lt;T&gt; 替换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;
;

【讨论】:

ty - 实际上 get_deleter() 提示是我正在寻找的(我知道如何在 MQueue 中使用 unique_ptr - 相反,我试图弄清楚如何允许用户通过传入/不传入 unique_ptr 作为实例化参数)。 如果它可能拥有或不拥有它 std::shared_ptr 会更有意义

以上是关于如何创建一个可以将 std::unique_ptr 作为模板参数正常工作的容器?的主要内容,如果未能解决你的问题,请参考以下文章

使用已使用 new X() 创建的变量将 std::unique_ptr 传递给函数

如何将 std::sort() 与 std::unique_ptr<[]> 一起使用?

std::将 std::unique_ptr 移动到 stl 容器中。 (MSVC 编译器问题)

如何在构造函数中使用删除器初始化 std::unique_ptr?

如何将unique_ptr存储在队列中

将 std::unique_ptr 的子类与 std::variant 一起使用