2015-05-21 2 views
0

Возможно, следующий код считается безопасным?Ссылка на статическую локальную переменную функции

Foo& GetFoo() 
{ 
    static std::once_flag fooInitFlag; 
    static Foo f; 

    std::call_once(fooInitFlag, [&Foo]() 
    { 
     Foo.Init(); 
    }); 

    return std::ref(f); 

} 
+5

Вам не нужно 'once_flag' вещь. Единая инициализация гарантирована. Использовать конструктор, а не метод 'Init' - –

+0

Да. Обратите внимание, что вам все еще нужно, что в msvc 2013, но не в компиляторе C++ 11, где статическая инициализация является потокобезопасной. (не возвращайте std :: ref (f), просто f) –

+1

Здесь вам не нужно 'std :: ref'; просто верните 'f'. И это безопасно, так как 'f' останется. –

ответ

2

Вы спросили:

Является ли следующий код считается безопасным?

Ответ на этот вопрос да.

Другая реализация:

// Not exposed to the outside. 
static Foo& getInitializedFoo(); 
{ 
    static Foo f; 
    f.Init(); 
    return f; 
} 

Foo& GetFoo() 
{ 
    static Foo& f = getInitializedFoo(); 
    return f; 
} 
+0

как насчет, 'static Foo &' (reference), чтобы избежать копирования. Я думаю, что это просто опечатка. –

+0

@ Cheersandhth.-Alf, я имел в виду вспомогательную функцию для возврата объекта по значению. –

+0

Ну, это будет работать так же, как и ссылка (та же самая инициализационная гарантия), 'static' Foo и более эффективная + меньшая вероятность побочного эффекта. Нижняя сторона, что 'getInitializedFoo', является внутренней детализацией реализации, которую можно вызвать только один раз. –

3

Вместо этого отправил код:

Foo& GetFoo() 
{ 
    static std::once_flag fooInitFlag; 
    static Foo f; 

    std::call_once(fooInitFlag, [&Foo]() 
    { 
     Foo.Init(); 
    }); 

    return std::ref(f); 
} 

сделать это:

struct Initialized_foo 
{ 
    Foo item; 
    Initialized_foo() { item.Init(); } 
}; 

auto get_foo() 
    -> Foo& 
{ 
    static Initialized_foo the_foo; 
    return the_foo.item; 
} 

Это не более безопасно, но это проще, и, следовательно, более безопасным в отношении непреднамеренно введенных ошибок.

Обратите внимание, что стандарт гарантирует единственную инициализацию здесь, даже в контексте многопоточности.


лучше, в идеале каждый Foo insteance должен быть надлежащим образом инициализируется Foo конструктора, а не с помощью метода Init. Но это не всегда возможно.

+0

Вы забыли 'the_foo.item' –

+0

@ThePhD: спасибо, исправлено. –

+0

И 'static Initialized_foo the_foo;'. –

Смежные вопросы