2

In C++, I can implement lazy initialisation with static:

struct foo { ... };
foo create_foo();
const foo& get_foo() {
    static foo x = create_foo();
    return x;
}

Here, initialisation occurs the first time get_foo is called (lazy), get_foo is guaranteed to be thread safe, and initialisation is guaranteed to only occur once. Specifically:

[stmt.dcl] "Dynamic initialization of a block-scope variable with static storage duration ... is performed the first time control passes through its declaration ... if control enters the declaration concurrently ... the concurrent execution shall wait for completion of the initialization"

How can I get the same behaviour in standard C?

konsolas
  • 1,041
  • 11
  • 24
  • 1
    Are you sure? I would expect that all static objects are initialized _before_ `main()` is called. What does the standard say? -- The common solution is to use a pointer initialized to `nullptr` (`NULL` in C) and then to act accordingly. – the busybee Jan 02 '22 at 16:20
  • 1
    [stmt.dcl] "Dynamic initialization of a block-scope variable with static storage duration ... is performed the first time control passes through its declaration ... if control enters the declaration concurrently ... the concurrent execution shall wait for completion of the initialization" – konsolas Jan 02 '22 at 16:25
  • @konsolas, it's probably best to edit your question with that quote. – Elliott Jan 02 '22 at 16:30

1 Answers1

1

In C, there are no references, and you have to type struct, and you have to take care of initialization.

#include <stdbool.h>
struct foo { int a; };
struct foo create_foo();
const struct foo* get_foo() {
    static bool initialized = false;
    static struct foo x;
    if (!initialized) {
        initialized = true;
        x = create_foo();
    }
    return &x;
}

To be thread-safe, you can use call_once. Sadly, with a global variable.

#include <threads.h>
struct foo { int a; };
struct foo create_foo();

static struct foo global_x;
static void init_global_x(void) {
    global_x = create_foo();
}
const struct foo* get_foo() {
    static once_flag global_x_initialized = ONCE_FLAG_INIT;
    call_once(&global_x_initialized , init_global_x);
    return &global_x;
}
KamilCuk
  • 120,984
  • 8
  • 59
  • 111