1

In this question, it's advocated to use non-class functions: Using non-member methods in C++

It's also quite common to see variables in the CPP file that are local to that file module, global vars local to that compilation unit, these can be initialized in-place

But what if I want to have an init-function in my CPP file, that serves the same purpose.

e.g. a contrived simple example

int x = 6; //this is initialized at program startup
int y = 8;

Compared to

int x,y;
void Init() //I want this to be called at startup
{
 //in practice this would do some more complicated stuff that isn't just init a var
 x=6;
 y=8;
}

How can I get Init() called at startup?

Mr. Boy
  • 60,845
  • 93
  • 320
  • 589
  • Something like: `static bool b = Init(), true;`. – Jarod42 Feb 15 '21 at 11:24
  • Ideas I had included make `Init` return a value so I can do `int dummy = Init()` or put it in a class ctor and then have `MyHelperClass M` – Mr. Boy Feb 15 '21 at 11:24
  • @Jarod42 I'm not sure I understand that syntax – Mr. Boy Feb 15 '21 at 11:26
  • 1
    what Jarod suggests is similar to the solution in the answer, its using the [comma operator](https://stackoverflow.com/questions/54142/how-does-the-comma-operator-work). A matter of taste which one you consider more obscure ;) – 463035818_is_not_an_ai Feb 15 '21 at 11:30
  • 3
    If you are going to use such methods a lot, in different files, beware of the [static initialization order fiasco](https://en.cppreference.com/w/cpp/language/siof) – Yksisarvinen Feb 15 '21 at 11:33
  • @largest_prime_is_463035818 oh yes, thanks. Not sure I've seen the comma-operator used 'in anger' before except for normal declare/init uses – Mr. Boy Feb 15 '21 at 11:43
  • @Yksisarvinen that's a dead link for me – Mr. Boy Feb 15 '21 at 11:45
  • Strange, it's a link to cppreference. How about this one: https://isocpp.org/wiki/faq/ctors#static-init-order ? – Yksisarvinen Feb 15 '21 at 12:02
  • If the object is declared in my source (rather than header) file it is effectively private to that file/unit, right? So if it is only used by methods in this file, is SIOF actually an issue @Yksisarvinen – Mr. Boy Feb 15 '21 at 12:44
  • @Mr.Boy If you declare the variable with external linkage such as in the example, then it is effectively public to all translation units. – eerorika Feb 15 '21 at 12:45
  • 2
    SIOF is one thing, and it's not an issue if you only ever use the variables from within one file. But I know from experience that this can quickly become a dead rule and it's hard to detect/enforce. But there's another thing, if you don't declare variable as `static` or `constexpr` or in anonymous namespace, it's not private to that file and you may have issues with ODR violation (if there would be two such variables with same names). – Yksisarvinen Feb 15 '21 at 12:49
  • To insist on the SIOF, almost any time I tried to use *indirect data initialization* (one data being initialized as a side effect of initializing a different one) I ended in a trap... C++ ensures that every variable will be initialized before it is used, but it is its only guarantee... – Serge Ballesta Feb 15 '21 at 13:19
  • @SergeBallesta `C++ ensures that every variable will be initialized before it is used` That's kinda misleading. In the context of variables in static storage, they are indeed guaranteed to be zero-initialised, C++ doesn't (in general) guarantee that the dynamic initialisation would be performed before the variable is used until `main`. And if taken out of context, automatic variables can be default initialised which is practically same as not initialised. – eerorika Feb 15 '21 at 13:24
  • @eerorika: You are right, of course. I wanted to insist that relying on indirect initialization is even braver and could not find a correct wording for that (I am sorry, but English is not my first language...) – Serge Ballesta Feb 15 '21 at 13:27

2 Answers2

4

You can try something like this:

static bool inited = [](){
 Init();
 return true;
}();
Martin Perry
  • 9,232
  • 8
  • 46
  • 114
2

How to call a one-time init function

A simple example:

namespace {

int init() {
    // in practice this would be more complex
    return 6;
}

int x = init();

}

However, using dynamic initialisation is not recommended for external namespace scope variables because they are susceptible to Static Initialisation Order Fiasco. As such, a local static is a better alternative for external variables:

int& x() {
    static int value = init();
    return value;
}

There isn't a "the value" [edited question has multiple values]

Regarding edited question: This is what classes are for. Example:

struct descriptive_class_name {
    int x;
    int y;
};

namespace {

descriptive_class_name
init() {
    // in practice this would be more complex
    return {
        .x = 6,
        .y = 8,
    };
}

}


descriptive_class_name&
descriptive_variable_name() {
    static descriptive_variable_name value = init();
    return value;
}
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • this doesn't quite capture the desired result, which in my case is that `x` is guaranteed to be set when I use it. In real life `Init` might do more complex logic like create and populate some complex data-structures, it can't just return the value. I _think_ your premise still applies – Mr. Boy Feb 15 '21 at 12:34
  • @Mr.Boy The latter guarantees that the value is initialised because the only way to get the value is to call the function that initialises the value. The former guarantees that the value is initialised before the value is accessed if `main` has been called, but there is no guarantee if you want to access the object during static initialisation phase across TU (this is the Static Initialisation Order Fiasco). Therefore I recommend the latter. – eerorika Feb 15 '21 at 12:36
  • @Mr.Boy You don't need to "just" return the value. You can have the complex population of data-structures and **then** return the value. – eerorika Feb 15 '21 at 12:42
  • There isn't a "the value", is my point - `init` might manage many variables. As I say the premise of 'wrapping' within a method still makes sense though. I've tweaked my question to clarify what I mean – Mr. Boy Feb 15 '21 at 13:06
  • Yeah that makes sense - I was thinking this sort of line from your original answer but it's useful to have it explicit. Thank-you. – Mr. Boy Feb 15 '21 at 13:17