"Do not use Static Constructors" LLVM Coding Standard rule question


I’m new here and have a question about the rule in title. Is the following use case also prohibited?

int findNameId(StringRef Name)
static StringMap Map = createSomeIDMap();
return Map.lookup(Name);

It seems it isn’t influence startup time and doesn’t create initialization order problems. Clang isn’t complaining about it with -Wglobal-constructor flag.

I’m asking because under some interpretation of rule wording it can be called static constructor too.


I believe the rule is only for global variables. At least that’s what the first sentence in the section says.

“Static constructors and destructors (e.g. global variables whose types have a constructor or destructor) should not be added to the code base, and should be removed wherever possible.”

a static local still produces a static dtor, though

One of the ways you can get around this is with a deliberate non-cleanup:

const foo &getFoo() {
static const foo &f = *new foo();
return f;

that way no global dtor runs. Obviously only works if you don’t need foo’s dtor to run.

Right, but it produces a mem leak, I’m not sure what is worse :slight_smile:

These type of constructs are less than ideal if you have something that uses LLVM as a library in a “long running” application (e.g. imagine something like photo editor that compiles “filters”, and a user that loads the application on monday, and closes it on the following thursday) , as there is no (trivial) way to know that this stringmap exists, or that it may need cleaning out between two compilations, for example. The risk with such constructs is that they build up over time, and appear to be “memory leaks”.

Thanks, this is a good reasoning, will avoid static local objects.


Oh, yes, for sure. This should not be used for any dynamic state. Such a thing can only used as an immutable singleton of sorts.

If it is mutable then you break the usual thread safety guarantees -two separate threads using two separate llvm contexts shouldn’t interfere with each other.

Not to mention, as you said, can break ongoing uses of llvm by accumulating cruft. That’s what the llvmcontext is for - all that mutable state we can’t find a better place for :wink:

The leak itself is acceptable though, if those conditions are met. So if you just need the map for some fixed lookup table, the solution I suggested should be OK. It won’t produce an unrecoverable growing memory drain, etc.

I would not recommend the leaky static construct (e.g. “static const foo &f = *new foo();”). If LLVM is built as a dynamic library, it can be unloaded and reloaded an indefinite number of times, and each one of those iterations will leak one instance of ‘foo’.

Also, if LLVM is built by Windows MSVC 2013 (which LLVM supports), then function level static creation is not thread safe (it is thread safe with MSVC 2015). This can really get you in trouble if you also use LTO, as some LTO variants will internally create a thread for each object.