嘗試#2B:實現自己的std::once_flag
當量,與atomic<int>
(Live at Rextester):
my_type const& instantiate() {
static std::aligned_storage<sizeof(my_type), __alignof(my_type)>::type storage;
static std::atomic_int flag;
while (flag < 2) {
// all threads spin until the object is properly initialized
int expected = 0;
if (flag.compare_exchange_weak(expected, 1)) {
// only one thread succeeds at the compare_exchange.
try {
::new (&storage) my_type;
} catch(...) {
// Initialization failed. Let another thread try.
flag = 0;
throw;
}
// Success!
if (!std::is_trivially_destructible<my_type>::value) {
std::atexit([] {
reinterpret_cast<my_type&>(storage).~my_type();
});
}
flag = 2;
}
}
return reinterpret_cast<my_type&>(storage);
}
這僅依賴於編譯器正確零初始化所有靜態存儲持續時間的對象,並且還使用了非標準擴展__alignof(<type>)
以正確對齊storage
,因爲微軟的編譯團隊不會被打擾添加沒有兩個下劃線的關鍵字。
嘗試#1:在具有
std::once_flag
(
Live demo at Coliru)結合使用
std::call_once
:
my_type const& instantiate() {
struct empty {};
union storage_t {
empty e;
my_type instance;
constexpr storage_t() : e{} {}
~storage_t() {}
};
static std::once_flag flag;
static storage_t storage;
std::call_once(flag, []{
::new (&storage.instance) my_type;
std::atexit([]{
storage.instance.~my_type();
});
});
return storage.instance;
}
爲std::once_flag
默認的構造是constexpr
,所以它保證恆定初始化期間來構造。我覺得VC正確執行不斷的初始化。編輯:不幸的是,通過VS12的MSVC仍然不支持constexpr
,所以這種技術有一些未定義的行爲。我會再嘗試。
C++ 11 [stmt.dcl/4不是無聲:」 ......這樣的變量是 首次初始化控制穿過它的聲明;這樣的變量被認爲是在 完成初始化如果初始化通過拋出異常退出,則初始化 未完成,因此在下一次控制進入聲明時將再次嘗試初始化。如果控制在初始化變量時並行輸入 ,則併發執行應等待 完成初始化。「 – Casey