電子書籍の厳選無料作品が豊富!

標準C++でシングルトンを実装したいのですが。
class Singleton{
public:
static Singleton* getInstance(){
if (_instance == NULL){
//スレッドAがこの時点で、スレッドBがNULLチェックすると破綻する
_instance = new Singleton();
}
return _instance;
}
private:
Singleton();
static Singleton* _instance;
};
マルチスレッドになると上記のパターンで破綻するといわれどうしたものかと考えております。
static Singleton* _instance = new Singleton();
と出来れば解決なのですが
「static const int データメンバ以外をクラス内で初期化することはできません」
とのことでそれもできず。
どのようにすればよいでしょうか。

A 回答 (3件)

 こんにちは。

すんません、的外れな事を書いてしまいました。

・「static const int データメンバ以外をクラス内で初期化することはできません」
 と言うのは、staticメンバ変数の初期化手段を間違えているからではないでしょうか。
 ヘッダの中で初期化するのではなく、改めてソースの中に、

 Singleton* Singleton::_instance = new Singleton();

 と書きます。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
こちらこそ申し訳ありません。
想像していたよりも複雑なコードが返ってきて戸惑っておりました。
>ヘッダの中で初期化するのではなく、改めてソースの中に、
より、
Singleton.class---------
class StringPlus{
public:
static StringPlus* StringPlus::instance(){
return _instance;
}
private:
StringPlus(){}
static StringPlus* _instance;
};
Singleton.cpp-----------------
StringPlus* StringPlus::_instance = new StringPlus();
で解決、と私は思っていたのですが・・・あれ?

お礼日時:2009/10/19 13:15

> どのようにすればよいでしょうか?


・シングルトンの使用をやめる。
・シングルトンのインスタンスがスレッド群に参照される前に必ず初期化されることを保証する手順を考える。
ですかね。

Double checked lockingという手法があるようですが、
http://www.sun-inet.or.jp/~yaneurao/yaneSDK3rd/c …

そこにも穴があって、完璧なシングルトンをマルチスレッドで
実装するのは、C++だけでは無理なよう。理由は以下を参照。
http://qo.sakuratan.com/2008/09/03/doublecheaklo …
    • good
    • 0
この回答へのお礼

ありがとうございます。
スレッドの流れを一旦止める、なんて手段をとっているんですね。
ダブルまではわかるのですがトリプルにする意味がよくわかりませんでした。

>実装するのは、C++だけでは無理なよう。理由は以下を参照。
C++への理解が足らないようでほとんど理解出来ませんでした。
いずれにせよ現時点で完璧なシングルトンは考えない方がよさそうですね。(私自身の未熟さ故)

お礼日時:2009/10/19 15:53

 こんにちは。


 例えば、windowsの場合では以下の様な感じです。雑ですが、参考程度に。

class Exclusive
{
public:
virtual ~Exclusive(){}
virtual bool lock() = 0;
virtual bool unlock() = 0;
};

//排他リソースクラス(環境に応じて中を変える)
class Critical : public Exclusive
{
public:
Critical() : _block(false)
{
//排他リソース初期化
::InitializeCriticalSection(&_cs);
}

~Critical()
{
//排他リソース削除
::DeleteCriticalSection(&_cs);
}

bool lock()
{
//排他リソースロック
if(_block)return false;
::EnterCriticalSection(&_cs);
_block = true;
return true;
}

bool unlock()
{
//排他リソース解除
if(!_block)return false;
::LeaveCriticalSection(&_cs);
_block = false;
return true;
}

private:
bool _block;
CRITICAL_SECTION _cs;
};

//コンストラクタ/デストラクタを利用して排他リソースクラスのlock()/unlock()を呼び出すクラス
class Block
{
public:
explicit Block(Exclusive* p) : _p(p)
{
_p->lock();
}

~Block()
{
_p->unlock();
}
private:
Exclusive* _p;
};

//シングルトン
class Singleton
{
public:
static Singleton* getInstance()
{
//ココでブロックする
volatile Block block(&_critical);

if(_instance == NULL)
{
_instance = new Singleton();
}
return _instance;
}
private:
Singleton(){}
static Singleton* _instance;
static Critical _critical;
};

//staticメンバの初期化
Singleton* Singleton::_instance = NULL;
Critical Singleton::_critical;

//スレッド内で使用する
Singleton* p = Singleton::getInstance();
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!