0

I want to realize a singleton-like functionality using std::call_once just for fun or perhaps could improve on the Singleton Pattern itself. Here's what I tried so far but I am stuck. Any help will be highly appreciated.

class single {
public:

private:
    single(){}
    friend void boo(unique_ptr<single>&);
};

void boo(unique_ptr<single>& f) {
    f.reset(new single());
}

unique_ptr<single>& bar() {
    static once_flag flag;
    static unique_ptr<single> f;
    call_once(flag, boo,f);
    return f;
}


int main()
{
    unique_ptr<single> f;
    f = move(bar());

    unique_ptr<single> f2;
    f2 = move(bar()); // this should not work but it does, work-around?
}
ark1974
  • 615
  • 5
  • 16
  • 1
    Looks like a duplicate: https://stackoverflow.com/questions/26985370/stdcall-once-vs-stdmutex-for-thread-safe-initialization – Frederik De Ruyck Sep 21 '18 at 11:42
  • @FrederikDeRuyck: The link excepted an answer without call_once – ark1974 Sep 21 '18 at 11:49
  • 1
    As I read your code, the first time you call bar, the single tone will be returned, but the next time you call bar, bar return an empty unique_ptr, this is not usual. – Oliv Sep 21 '18 at 11:53
  • @Oliv: Yes your are right, I try using a Static there. Wow it compiles at least. I want to hide boo() in a namespace. but after move(bar() in main() the instance in bar may be in problem – ark1974 Sep 21 '18 at 11:56
  • So now consider that the standard ensures that static locals to function (as is `f`) are only initialized once. So there is some form of code duplication here. – Oliv Sep 21 '18 at 12:01
  • @Oliv: move(bar() in main should put the static unique_ptr f in UB, but it works a second time – ark1974 Sep 21 '18 at 12:02
  • So I did not know you intented to do that, so go back to f non static. – Oliv Sep 21 '18 at 12:04

1 Answers1

2

static is enough. It does thread-safe initialization for you, no need for call_once:

If multiple threads attempt to initialize the same static local variable concurrently, the initialization occurs exactly once (similar behavior can be obtained for arbitrary functions with std::call_once).

Note: usual implementations of this feature use variants of the double-checked locking pattern, which reduces runtime overhead for already-initialized local statics to a single non-atomic boolean comparison.

Hence:

unique_ptr<single>& bar() {
    static unique_ptr<single> f{new single};
    return f;
}

Or better:

single& bar() {
    static single f;
    return f;
}
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271