如何安全地重载 std::unique_ptr 的自定义删除器?

How can I safely overload custom deleter of std::unique_ptr?

我试图在使用 std::unique_ptr 和它的自定义删除器时减少代码重复。

我有一些容器 FooBar 是使用 one 自定义分配器分配的,因此无法使用 delete 释放。

所以当前代码是:

struct UniqueFooDeleter
{
   void operator()(Foo* foo) 
   {
      internal_free(foo);
   }
};
using unique_foo_ptr = std::unique_ptr<Foo, UniqueFooDeleter>;

struct UniqueBarDeleter 
{
   void operator()(Bar* bar) 
   {
      internal_free(bar);
   }
};
using unique_bar_ptr = std::unique_ptr<Bar, UniqueBarDeleter>;

我改成了:

struct UniqueInternalDeleter
{
   void operator()(Bar* bar)
   {
      internal_free(bar);
   }

   void operator()(Foo* foo)
   {
      internal_free(foo);
   }
};
using unique_bar_ptr = std::unique_ptr<Bar, UniqueInternalDeleter>;
using unique_foo_ptr = std::unique_ptr<Foo, UniqueInternalDeleter>;

我怎样才能做得更好,以便通过 internal_free 分配的任意数量的容器都可以用作 std::unique_ptr

如果 T 不是 Foobar.

,您可以将 UniqueInternalDeleter 作为模板仿函数和 static_assert
#include <type_traits> // std::is_same_v

template<typename T>
struct UniqueInternalDeleter /* final */
{
   static_assert(std::is_same_v<T, Foo> || std::is_same_v<T, Bar>,
      " T must be either Foo or Bar");

   void operator()(T* barOrfoo)
   {
      internal_free(barOrfoo);
   }

private:
   void internal_free(T* barOrfoo)
   {
      if constexpr(std::is_same_v<T, Foo>)
         // code for `Foo*`
      else
         // code for `Bar*`

   }
};

这使得您的别名对于 BarFoo 更具体:

using unique_bar_ptr = std::unique_ptr<Bar, UniqueInternalDeleter<Bar>>;
using unique_foo_ptr = std::unique_ptr<Foo, UniqueInternalDeleter<Foo>>;

一种可能的方法:

template<class> struct needs_internal_free : std::false_type { };

struct unique_internal_deleter {
    template<class T>
    void operator()(T* ptr) const {
        static_assert(needs_internal_free<T>::value);
        internal_free(ptr);
    }
};

template<class T>
using unique_internal_ptr = std::unique_ptr<T, unique_internal_deleter>;

现在我们可以声明具体类型了:

template<> struct needs_internal_free<Foo> : std::true_type { };
using unique_foo_ptr = unique_internal_ptr<Foo>;

template<> struct needs_internal_free<Bar> : std::true_type { };
using unique_bar_ptr = unique_internal_ptr<Bar>;