template<typename T>
static const Metatype* get_metatype() {
static const Metatype* mt = []() {
constexpr size_t name_hash = Metatype::build_hash<T>().name_hash;
auto type = metatype_cache.find(name_hash);
if (type == metatype_cache.end()) {
constexpr Metatype newtype = Metatype::build<T>();
metatype_cache[name_hash] = newtype;
}
return &metatype_cache[name_hash];
}();
return mt;
}
Variable mt initialized by lambda's return value. Why not just extract lambda code and make it part of get_metatype() function then just return value from it? Is this some performance trick or what??
This code from decs https://github.com/vblanco20-1/decs project that i am learning for educational purposes.
The variable mt
is declared static
, meaning that there is only one instance (with static storage duration) of mt
for each T
in the program or in each translation unit (depending on whether the function shown is a static
function in a class or at namespace scope) and if the function get_metatype<T>()
is called multiple times in the program, only the first call reaching mt
's declaration will execute mt
's initializer and initialize mt
. The other calls will simply return the then-fixed value of mt
. This is even guaranteed to hold when multiple threads are involved, without the initializer ever being called in two of the threads.
Using a directly-invoked lambda in the initializer allows one to put all the code that should be executed only once to initialize the variable mt
in one place inline without having to create a new function for it. If you put the statements inside the lambda directly in the body of get_metatype<T>()
, then they would be executed each time the function is called and not only once, and the responsibility of avoiding data races in the initialization when multiple threads are involved would shift to you.
In particular, possible reasons for using the static
mt
here might be that there are multiple threads and a data race on the construction of the the "metatype" must be avoided, although there would still seem to be a race condition or even a data race on metatype_cache
if multiple calls to get_metatype<T>()
for different T
are made, because the find
and the placement into the container are not done atomically.
Or a possible reason could be that the lookup operations into get_metatype
take too long to execute each time get_metatype
is called, although a static
variable is not the best choice for performance optimization either, since it requires thread-safe checks on each call to verify whether mt
has already been initialized.