C++ 11では、ロックが不要です。並行実行は、静的ローカル変数がすでに初期化されている場合に待機します。
§6.7 [stmt.dcl] p4
変数が初期化されている間に制御が同時に宣言を入力した場合、同時実行は、初期化の完了を待たなければなりません。
§6.7 [stmt.dcl] p4
静的記憶期間を持つすべてのローカルオブジェクト(3.7.1)のゼロ初期化(8.5)である:我々はこれを持っているC++ 03
他の初期化が行われる前に実行されます。定数式で初期化された静的記憶期間を持つPODタイプ(3.9)のローカルオブジェクトは、ブロックが最初に入力される前に初期化されます。実装では、 実装が名前空間スコープ(3.6.2)で静的ストレージ期間を持つオブジェクトを静的に初期化することが許可されているのと同じ条件下で、静的ストレージ期間を持つ他のローカルオブジェクトの早期初期化を実行できます。 そうでなければ、そのようなオブジェクトは、最初のコントロールがその宣言を通過するときに初期化されます。
最後の部分は、コードに適用されるため重要です。コントロールが最初にget_class_instance()
に入ると、最初にクリティカルセクションの初期化を経て、シングルトンの宣言(クリティカルセクション内で初期化されます)を通過し、クリティカルセクションの初期化をパスします。
理論的には、コードは安全でなければなりません。
これで、すべての関数呼び出しでクリティカルセクションを入力しなくても、これを改善できます。 @Chethanの基本的な考え方は健全なので、それを基にします。しかし、動的割り当ても避けています。そのために、しかし、我々はBoost.Optionalに頼っている:
#include <boost/optional.hpp>
Class& get_class_instance() {
static boost::optional<Class> c;
static bool inited;
if (!inited){
EnterCriticalSection(&cs);
if(!c)
c = Class(data);
LeaveCriticalSection(&cs);
inited = true;
}
return *c;
}
Boost.Optionalは、デフォルトの初期化を回避し、二重のチェックがすべての関数呼び出しのクリティカルセクションに入る避けることができます。しかし、このバージョンでは、代入でClass
のコピーコンストラクタへの呼び出しが導入されています。そのソリューションは、工場内にあります。
#include <boost/utility/in_place_factory.hpp>
#include <boost/optional.hpp>
Class& get_class_instance() {
static boost::optional<Class> c;
static bool inited;
if (!inited){
EnterCriticalSection(&cs);
if(!c)
c = boost::in_place(data);
LeaveCriticalSection(&cs);
inited = true;
}
return *c;
}
@Rに感謝します。この最終的なソリューションに協力したMartinho Fernandesと@Ben Voigtプロセスに興味がある場合は、transcriptをご覧ください。あなたのコンパイラは、静的初期のものをすでにC++ 11の機能の一部をサポートしていますが、ない場合は
さて、あなたはまた、std::unique_ptr
を使っ配置新しいと静的整列バッファと組み合わせることができます。
#include <memory> // std::unique_ptr
#include <type_traits> // alignment stuff
template<class T>
struct destructor{
void operator(T* p) const{
if(p) // don't destruct a null pointer
p->~T();
}
};
Class& get_class_instance() {
typedef std::aligned_storage<sizeof(Class),
std::alignment_of<Class>::value>::type storage_type;
static storage_type buf;
static std::unique_ptr<Class, destructor> p;
static bool inited;
if (!inited){
EnterCriticalSection(&cs);
if(!p)
p.reset(new (&buf[0]) Class(data));
LeaveCriticalSection(&cs);
inited = true;
}
return *p;
}
出典
2012-01-02 03:41:46
Xeo
この編集では、関連性がなくなったため、回答を削除する必要があります。 :P – Xeo
@Xeo申し訳ありませんが、より具体的なはずですが、私はC++ 11のその機能をサポートしていないコンパイラを扱っていますが、私はあなたの答えをupvoted、ありがとう –