具有非指针资源的shared_ptr

shared_ptr with non-pointer resources

本文关键字:shared ptr 资源 指针      更新时间:2023-10-16

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


可以使用unique_ptr来管理非指针资源。这是通过实现一个自定义的deleter类来实现的,该类提供:

  1. typedef {TYPE} pointer;,其中{TYPE}是非指针资源类型
  2. 释放受控资源的operator()(pointer)

然后以自定义删除器作为第二模板参数来实例化CCD_ 6。

例如,在Windows下,可以创建一个unique_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构造函数重载提供了提供自定义deleter类的方法,但没有一个构造函数接受不是指针或指针周围包装的资源类型。

如何做到这一点?

遗憾的是,shared_ptr对类型擦除的需求使得当前接口无法实现您想要的unique_ptr之所以能够做到这一点,是因为它有关于实际deleter类型的静态信息,可以从中绘制实际的"指针"类型。在shared_ptr的情况下,deleter类型在类型擦除过程中丢失(这就是为什么不能在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; });

好吧,一旦对指针的最后一次引用被释放,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保持最佳状态。

这个怎么样?

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

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

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

模板<类Y,类Deleter>shared_ptr(Y*ptr,Deleter d);

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

不要这样想。因为标准为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()的值为释放调用的开始。

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