Как я могу безопасно перегрузить пользовательский модуль удаления std :: unique_ptr? - PullRequest
2 голосов
/ 01 августа 2020
• 1000 распределитель, поэтому его нельзя освободить с помощью 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 s?

Ответы [ 2 ]

3 голосов
/ 01 августа 2020

Вы можете сделать UniqueInternalDeleter шаблонным функтором и static_assert, если T не Foo или bar.

#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*`

   }
};

Это делает ваш псевдоним будет более конкретным c для Bar и Foo:

using unique_bar_ptr = std::unique_ptr<Bar, UniqueInternalDeleter<Bar>>;
using unique_foo_ptr = std::unique_ptr<Foo, UniqueInternalDeleter<Foo>>;
2 голосов
/ 01 августа 2020

Один из возможных подходов:

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

Теперь мы можем объявить специфицированные c типы:

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