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;
}
变量mt由lambda的返回值初始化。为什么不只提取lambda代码并将其作为get_metatype()函数的一部分,然后仅从中返回值呢?这是一些性能技巧吗?
This code from decs https://github.com/vblanco20-1/decs project that i am learning for educational purposes.
In addition to what @cigien said - a static variable is initialized only once. C++11 and later ensure that initialization is performed in a thread-safe manner. Using a lambda for the initializer ensures that the lambda is called only once. If you were to inline the lambda's code directly in
get_metatype()
, you would be responsible for manually serializing the code yourself, such as with a mutex.The variable
mt
is declaredstatic
, meaning that there is only one instance (with static storage duration) ofmt
for eachT
in the program or in each translation unit (depending on whether the function shown is astatic
function in a class or at namespace scope) and if the functionget_metatype<T>()
is called multiple times in the program, only the first call reachingmt
's declaration will executemt
's initializer and initializemt
. The other calls will simply return the then-fixed value ofmt
. This is even guaranteed when multiple threads are involved.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 ofget_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 accessmetatype_cache
orMetatype::build<T>
must be avoided or a possible reason could be that the lookup operations intoget_metatype
take too long to execute each timeget_metatype
is called, although astatic
variable is not the best choice for performance optimization either, since it requires thread-safe checks on each call to verify whethermt
has already been initialized.This is commonly used to initialize a variable that needs to be
const
, but is also complex to initialize. e.g.without doing this, there's no good way to make
v
const
.However, in your case, the reason for using this technique in the provided example, is so that the static variable
mt
is not initalized on every call toget_metatype
, as pointed out by @walnut, and @Remylebeau.