LoginSignup
0
0

More than 5 years have passed since last update.

Singletonのアロケータを後から指定 (shared_ptrを使用したSingletonの実装の続き)

Last updated at Posted at 2016-06-28

新しいの書きました
アロケータを指定できて参照がなくなった時点で破棄されるSingleton

アロケータを後から指定

一応shared_ptrを使用したSingletonの実装の続きです。

allocate_sharedが使えないこともありかなり微妙な実装になります。

2016/06/29
shared_ptrを使用したSingletonの実装の方のコードを変更したのでこちらも変更しました。
deleterの中でデストラクタ呼び出しも指定なかったので修正ついでにallocator_traitsを使用したコードに書き換え。
でも派生クラスのコンストラクタがprivateだと結局construct使えずにplacement newするしかない。
どうにかならないものか。

実装

先にこんな感じのものを定義します

template <typename T>
struct singleton_allocator
{
  using type = std::allocator<T>;
};

singleton本体の実装はこんな感じ

template <typename T> class singleton
{
private:
  using allocator = typename singleton_allocator<T>::type;

protected:
  singleton() = default;

public:
  virtual ~singleton() = default;

  singleton( singleton const& ) = delete;
  singleton& operator=( singleton const& ) = delete;

public:
  static std::shared_ptr<T> get_instance()
  {
    auto ret_ptr = instance_.lock();
    if( ret_ptr )
    {
      return ret_ptr;
    }

    using traits = std::allocator_traits<allocator>;

    auto pointer = traits::allocate( allocator_, 1 );
    //traits::construct( allocator_, pointer );
    ::new( pointer ) T{};

    auto deleter = []( T* ptr ) {
      //traits::destroy( allocator_, ptr );
      ptr->~T();
      traits::deallocate( allocator_, ptr, 1 );
    };

    ret_ptr   = std::shared_ptr<T>( pointer, deleter );
    instance_ = std::weak_ptr<T>( ret_ptr );
    return ret_ptr;
  }

private:
  static std::weak_ptr<T> instance_;
  static allocator        allocator_;
}; // class singleton

template <typename T> std::weak_ptr<T>                 singleton<T>::instance_;
template <typename T> typename singleton<T>::allocator singleton<T>::allocator_;

内部でallocatorを持っているのとget_instance()の中身が前回と違うところです。

my_allocatorという名前のアロケータとAという名前のSingletonがあるとすと

class A; // 前方宣言

// 特殊化
template <> struct
singleton_allocator<A>
{
  using type = my_allocator<A>;
};

こうすることでAの時のアロケータを指定できる。
これは必ずAの定義前に書かなければならない。

まとめ

正直かなり面倒だけどアロケータの指定ができる。

他のことにも使えそう。

指定できないよりもできたほうが良いかなって思って書いてみたけどなかなか面倒。

ちなみに

template <typename T, typename Allocator> class singleton{ ... };

みたいなのはAllocatorの型が変わるとsingletonの型も変わってしまうので使わない。

追記

一応これでできる…

    auto pointer = traits::allocate( allocator_, 1 );
    struct impl : public<T> {};
    traits::construct( allocator_, reinterpret_cast<impl*>(pointer) );

これどうなんですかね。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0