Есть ли цель объявить лямбду с последующим немедленным вызовом для инициализации локальной переменной, используя ее возвращаемое значение? - PullRequest
0 голосов
/ 08 апреля 2020
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;
    }

Переменная мт инициализируется возвращаемым лямбда-значением. Почему бы просто не извлечь лямбда-код и сделать его частью функции get_metatype (), а затем просто вернуть значение из него? Это какой-то трюк с производительностью или как?

Этот код из проекта decs https://github.com/vblanco20-1/decs, который я изучаю в образовательных целях.

Ответы [ 3 ]

1 голос
/ 09 апреля 2020

В дополнение к тому, что сказал @cigien - переменная stati c инициализируется только один раз. C ++ 11 и более поздние версии гарантируют, что инициализация выполняется потокобезопасным способом. Использование лямбды для инициализатора гарантирует, что лямбда вызывается только один раз. Если бы вам пришлось встроить лямбда-код непосредственно в get_metatype(), вы бы сами отвечали за ручную сериализацию кода, например, с мьютексом.

1 голос
/ 09 апреля 2020

Переменная mt объявлена ​​static, что означает, что существует только один экземпляр (со стати c срок хранения) mt для каждого T в программе или в каждой единице перевода (в зависимости от является ли показанная функция функцией static в классе или в области пространства имен) и если функция get_metatype<T>() вызывается в программе несколько раз, только первый вызов, достигший объявления mt, выполнит mt ' s инициализировать и инициализировать mt. Другие вызовы просто вернут фиксированное значение mt. Это даже гарантированно сохраняется, когда задействованы несколько потоков, без инициализации, когда-либо вызванной в двух потоках.

Использование лямбда-выражения, вызываемого напрямую, в инициализаторе позволяет поместить весь код, который должен быть выполнен только один раз, чтобы инициализировать переменную mt в одном месте без необходимости создавать новую функцию для нее. Если вы поместите операторы внутри лямбда-выражения непосредственно в теле get_metatype<T>(), то они будут выполняться каждый каждый раз, когда вызывается функция, а не только один раз, и ответственность за предотвращение скачков данных при инициализации при участие нескольких потоков может сместиться к вам.

В частности, возможные причины использования static mt здесь могут заключаться в том, что существует множество потоков и гонка данных при построении «метатипа» его следует избегать, хотя все равно может показаться, что на metatype_cache существует состояние гонки или даже гонка данных, если выполняется несколько вызовов на get_metatype<T>() для разных T, поскольку find и размещение в контейнере не выполняется атомарно.

Или возможная причина может заключаться в том, что операции поиска в get_metatype выполняются слишком долго при каждом вызове get_metatype, хотя переменная static не лучший выбор для производительности Оптимизация тоже, так как она требует поточно-ориентированных проверок при каждом вызове, чтобы проверить, является ли * 1 030 * уже инициализирован.

1 голос
/ 08 апреля 2020

Обычно используется для инициализации переменной, которая должна быть const, но также сложна для инициализации. например,

const std::vector<int> v = [] {
   std::vector<int> vv;
   // ... very complicated logic to initialize vv
   // even could be IO, etc ...
   return vv;
}();

без этого, нет хорошего способа сделать v const.

Однако, в вашем случае, причина использования этой техники в представленном примере, так что переменная stati c mt не инициализируется при каждом вызове get_metatype, на что указывают @walnut и @ Remylebeau.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...