"정적 통계"기능이 아직 구현되지 않은 Visual Studio 2013을 사용 중이므로 로컬 정적 변수 초기화가 사용되지 않습니다. 아직 스레드로부터 안전합니다.로컬 정적 std :: once_flag 및 로컬 정적 포인터를 사용하여 정적 변수의 스레드 안전 초기화
std::unique_ptr<Foo> gp_foo;
std::once_flag g_flag;
Foo& GetInstance()
{
std::call_once(g_flag, [](){ gp_foo = std::make_unique<Foo>(); });
return *gp_foo;
}
하지만 정적 초기화의 순서로, 첫 번째 (문제를 gp_foo
및 g_flag
전역 변수를 가지고있는 아이디어를 좋아하지 않는다 : 그래서, 대신
Foo& GetInstance()
{
static Foo foo;
return foo;
}
의 나는 같은 것을 할 두 번째, 필요한 경우에만, 즉 GetInstance()에 대한 첫 번째 호출 이후에 변수를 초기화하고 싶습니다. 따라서 다음을 구현했습니다.
Foo& GetInstance()
{
// I replaced a smart pointer
// with a raw one just to be more "safe"
// not sure such replacing is really needed
static Foo *p_foo = nullptr;
static std::once_flag flag;
std::call_once(flag, [](){ p_foo = new Foo; });
return *p_foo;
}
그리고 (적어도 테스트를 통과 한) 작동하지만, 스레드 안전성이 확실하지 않습니다. 왜냐하면 여기서 정적 로컬 변수 p_foo
및 flag
을 여러 스레드로 초기화 할 때 동일한 잠재적 인 문제가 있기 때문입니다. nullptr
및 초기화가 std::once_flag
인 원시 포인터를 초기화하는 것은 Foo
의 생성자를 호출하는 것보다 더 결백 한 것처럼 보이지만 실제로 안전한지 여부를 알고 싶습니다.
마지막 코드 단편에 문제가 있습니까?
https를 반환하는 제안 : //codereview.stackexchange합니다. com/ – Blacktempel
[call_once on cppreference] (http://en.cppreference.com/w/cpp/thread/call_once)를 참조하십시오. 특히 글 머리 기호 2. – Simple
@Simple _ 그룹의 호출은 선택한 함수가 성공적으로 완료되기 전에 반환됩니다. 즉, 예외를 통해 종료되지 않습니다. _하지만 내 관심사는 std ::에 대한 것이 아닙니다. call_once가 아니라이 두 줄에 대해서 :'static Foo * p_foo = nullptr; std :: once_flag flag; ' – undermind