Skip to content

Instantly share code, notes, and snippets.

@remyroez
Created July 14, 2014 08:45
Show Gist options
  • Save remyroez/a13facc116345e9ed276 to your computer and use it in GitHub Desktop.
Save remyroez/a13facc116345e9ed276 to your computer and use it in GitHub Desktop.
C++11 と unique_ptr でシングルトン ref: http://qiita.com/remyroez/items/fd35e6af8fbbdbdd73c4
main begin
1: device()
device foo!
2: device foo!
3: device foo!
~device()
4: invalid instance.
5: device()
6: device foo!
7: beacon()
8: gadget()
gadget baz!
9: beacon bar!
main end
~gadget()
~beacon()
~device()
#include "singleton.h"
#include <stdio.h>
// 適当シングルトンクラス1
class device {
public:
DEFINE_SINGLETON(device);
void foo() { printf("device foo!\n"); }
~device() { printf("~device()\n"); }
private:
// コンストラクタは private に
device() { printf("device()\n"); }
// 一応 Non copyable
device(const device &) = delete;
device &operator =(const device &) = delete;
};
// 適当シングルトンクラス2(名前と出力テキストが違うのみ)
class beacon {
public:
DEFINE_SINGLETON(beacon);
void foo() { printf("beacon bar!\n"); }
~beacon() { printf("~beacon()\n"); }
private:
beacon() { printf("beacon()\n"); }
beacon(const device &) = delete;
beacon &operator =(const device &) = delete;
};
// 適当シングルトンクラス3(名前と出力テキストが違うのみ)
class gadget {
public:
DEFINE_SINGLETON(gadget);
void foo() { printf("gadget baz!\n"); }
~gadget() { printf("~gadget()\n"); }
private:
gadget() { printf("gadget()\n"); }
gadget(const device &) = delete;
gadget &operator =(const device &) = delete;
};
int main() {
printf("main begin\n");
// 初回のインスタンス取得時に、自動でインスタンス化する
printf("1: ");
device::instance()->foo();
// 明示的に受け取り、所有判定も行う
printf("2: ");
if (device::singleton p = device::instance()) {
p->foo();
}
// auto を使うときは明示的に参照にする
printf("3: ");
if (auto &p = device::instance()) {
p->foo();
}
// インスタンスを明示的に解放
device::destroy();
// 2回目以降のインスタンス取得時は有効とは限らない
printf("4: ");
if (device::singleton p = device::instance()) {
p->foo();
} else {
printf("invalid instance.\n");
}
// インスタンスを明示的に作成
printf("5: ");
device::create();
// できれば所有判定は行ったほうがよい
printf("6: ");
if (device::singleton p = device::instance()) {
p->foo();
}
// 二重に読んでも二重に作成されない
printf("7: ");
beacon::create();
beacon::create();
printf("8: ");
if (gadget::singleton p = gadget::instance()) {
p->foo();
}
printf("9: ");
if (beacon::singleton p = beacon::instance()) {
p->foo();
}
printf("main end\n");
// 解放順は初回のインスタンス化を行った逆順
// 途中で destroy して create しても変わらない
return 0;
}
// シングルトン定義マクロ
// マクロ使用後は public になるので注意
#define DEFINE_SINGLETON(TYPE_)\
private:\
using self_type = TYPE_;\
using unique_ptr = std::unique_ptr<self_type>;\
public:\
using singleton = const unique_ptr &;\
static singleton instance() {\
return ref();\
}\
static void create() {\
if (!ref()) ref() = make_unique();\
}\
static void destroy() {\
ref().reset();\
}\
private:\
template <typename... Args>\
static unique_ptr make_unique(Args&&... args) {\
struct temp : self_type { temp() : self_type() {} };\
return std::move(unique_ptr(new temp(std::forward<Args>(args)...)));\
}\
static unique_ptr &ref() {\
static unique_ptr p = make_unique();\
return p;\
}\
public:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment