shared_ptr与非指针资源

时间:2012-07-25 14:20:26

标签: c++ c++11 shared-ptr

在C ++ 11中,是否可以使用shared_ptr来控制非指针资源?


可以使用unique_ptr来管理非指针资源。这是通过实现自定义删除器类来完成的,该类提供:

  1. typedef {TYPE} pointer;其中{TYPE}是非指针资源类型
  2. operator()(pointer)释放受控资源
  3. ...然后使用自定义删除器作为第二个模板参数实例化unique_ptr

    例如,在Windows下,可以创建管理service control handleunique_ptr。调用delete但调用CloseServiceHandle()不会释放此句柄类型。以下是执行此操作的示例代码:

    自定义删除器

    struct SvcHandleDeleter
    {
        typedef SC_HANDLE pointer;
        SvcHandleDeleter() {};
    
        template<class Other> SvcHandleDeleter(const Other&) {};
    
        void operator()(pointer h) const
        {
            CloseServiceHandle(h);
        }
    };
    
    
    typedef std::unique_ptr<SC_HANDLE,SvcHandleDeleter> unique_sch;
    

    实例化

    unique_sch scm(::OpenSCManagerA(0, 0, SC_MANAGER_ALL_ACCESS));
    

    是否可以使用shared_ptr来控制非指针资源?

    根据文档,有shared_ptr constructor overloads提供了提供自定义删除器类的方法,但是没有一个构造函数接受的资源类型不是指针或指针周围的包装器。 / p>

    如何做到这一点?

4 个答案:

答案 0 :(得分:14)

可悲的是,shared_ptr需要进行类型擦除,因此当前界面无法实现完全您想要的内容。 unique_ptr设法做到这一点,因为它有关于实际删除器类型的静态信息,从中可以绘制实际的“指针”类型。在shared_ptr的情况下,删除类型在类型擦除过程中丢失(这就是为什么你不能在shared_ptr模板中指定它)。

另请注意,unique_ptr不提供shared_ptr之类的转换构造函数(例如template<class Y> shared_ptr(Y* p))。它不能这样做,因为pointer不一定是真正的指针类型,因此它不能限制可接受的内容(除非可能通过某些带有std::is_convertible_to的SFINAE或类似的东西......但我离题了。)

现在,一个明显的解决方法是简单地new资源句柄,就像它听起来一样愚蠢。 :/

std::shared_ptr<SC_HANDLE> sp(new SC_HANDLE(::OpenSCManagerA(0, 0, SC_MANAGER_ALL_ACCESS)),
    [](SC_HANDLE* p){ ::CloseServiceHandle(*p); delete p; });

答案 1 :(得分:5)

好吧,只要释放了对指针的最后一个引用,shared_ptr就会调用指向对象的析构函数,然后可以释放类包含的任何内容。做一个类可能是这样的:

struct SvcHandle
{
  typedef SC_HANDLE pointer;
  SvcHandle()
  :M_handle(::OpenSCManagerA(0, 0, SC_MANAGER_ALL_ACCESS))
  { }

  ~SvcHandle()
  {
      CloseServiceHandle(M_handle);
  }
private:
  pointer M_handle;
};

然后只需使用新的SvcHandle创建一个共享指针。 句柄的生命周期管理将与shared_ptr - RAII一起使用。

答案 2 :(得分:1)

这个怎么样?

auto scm = make_shared<unique_sch>(::OpenSCManagerA(0, 0, SC_MANAGER_ALL_ACCESS));

unique_sch 是您在问题中提到的课程。 现在使用scm作为资源的共享指针。 在需要时取消引用并不是最好的事情,但你确实询问它是否可行。

但是仍然使用指针。 从文档中可以看出, unique_ptr 类将指针类作为构造函数参数,实际上可以是任何东西。 然而, shared_ptr 将一个类型作为模板参数,并在其构造函数中强制将其转换为指向该类型的指针:

  

模板&LT; Y类,类Deleter&gt; shared_ptr( Y * ptr,Deleter d);

我认为可以说它不能直接用于管理非指针资源,因为 shared_ptr 类假设其资源是指针。

答案 3 :(得分:0)

不要。由于标准为shared_ptr提供了这样的构造函数而没有其他构造函数。

// 20.7.2.2.1, constructors:
constexpr shared_ptr() noexcept;
template<class Y> explicit shared_ptr(Y* p);
template<class Y, class D> shared_ptr(Y* p, D d);
template<class Y, class D, class A> shared_ptr(Y* p, D d, A a);
template <class D> shared_ptr(nullptr_t p, D d)
template <class D, class A> shared_ptr(nullptr_t p, D d, A a)
template<class Y> shared_ptr(const shared_ptr<Y>& r, T *p) noexcept;
shared_ptr(const shared_ptr& r) noexcept;
template<class Y> shared_ptr(const shared_ptr<Y>& r) noexcept;
shared_ptr(shared_ptr&& r) noexcept;
template<class Y> shared_ptr(shared_ptr<Y>&& r) noexcept;
template<class Y> explicit shared_ptr(const weak_ptr<Y>& r);
template<class Y> shared_ptr(auto_ptr<Y>&& r);
template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r);
constexpr shared_ptr(nullptr_t) : shared_ptr() { }

例如你想做什么(对于unique_ptr)

pointer release() noexcept;
  

1后置条件:get()== nullptr。 2返回:get()的值为   要求释放的开始。

没有指针资源?你试图破解语言。这总是坏主意。