exponenta event banner

CERT C++: EXP61-CPP

Лямбда-объект не должен переживать ни один из своих ссылочных захваченных объектов

Описание

Определение правила

Лямбда-объект не должен переживать ни один из своих ссылочных захваченных объектов. [1 ]

Внедрение Polyspace

Эта проверка проверяет область «» Escapes Object Scope Through Lambda Expression «».

Примеры

развернуть все

Проблема

Проблема возникает, когда лямбда-выражение захватывает объект по ссылке, а лямбда-выражение извлекает захваченный объект. Например, захваченный объект является локальной переменной, но объект лямбда-выражения имеет гораздо большую область действия.

Риск

Если объект лямбда-выражения переживает один из своих ссылочных захваченных объектов, доступ к захваченному объекту возможен за пределами его области действия.

Например, рассмотрим эту функцию createFunction:

std::function<std::int32_t()> createFunction() {
   std::int32_t localVar = 0;
   return ([&localVar]() -> std::int32_t {
       localVar = 1;
       return localVar;
   });
}

createFunction возвращает объект лямбда-выражения, который захватывает локальную переменную localVar по ссылке. Объем localVar ограничивается createFunction но возвращенный объект лямбда-выражения имеет гораздо большую область действия.

Эта ситуация может привести к попытке доступа к локальному объекту localVar за его пределами. Например, когда вы звоните createFunction и назначить возвращенный объект лямбда-выражения другому объекту aFunction:

auto aFunction = createFunction();
а затем вызовите новый объект aFunction:
std::int32_t someValue = aFunction();
захваченная переменная localVar больше не входит в область действия. Поэтому значение, возвращенное из aFunction не определен.

Зафиксировать

Если функция возвращает лямбда-выражение, чтобы избежать доступа к захваченному объекту вне его области действия, убедитесь, что лямбда-выражение захватывает все объекты копией. Например, можно переписать createFunction как:

std::function<std::int32_t()> createFunction() {
   std::int32_t localVar = 0;
   return ([localVar]() mutable -> std::int32_t {
       localVar = 1;
       return localVar;
   });
}

Пример - Указатель на локальную переменную через лямбда-выражение
auto createAdder(int amountToAdd) {
  int addThis = amountToAdd;
  auto adder = [&] (int initialAmount) {
      return (initialAmount + addThis);
  };
  return adder;
}
 
void func() {
  auto AddByTwo = createAdder(2);
  int res = AddByTwo(10);
}

В этом примере createAdder функция определяет лямбда-выражение adder который захватывает локальную переменную addThis по ссылке. Объем addThis ограничивается createAdder функция. Когда объект возвращен createAdder вызывается, ссылка на переменную addThis доступен за пределами его области действия. При обращении таким образом значение addThis не определен.

Исправление - захват локальных переменных копированием в лямбда-выражении вместо ссылки

Если функция возвращает объект лямбда-выражения, избегайте захвата локальных переменных по ссылке в лямбда-объекте. Захватите переменные путем копирования.

auto createAdder(int amountToAdd) {
  int addThis = amountToAdd;
  auto adder = [=] (int initialAmount) {
      return (initialAmount + addThis);
  };
  return adder;
}
 
void func() {
  auto AddByTwo = createAdder(2);
  int res = AddByTwo(10);
}

Проверить информацию

Группа: 02. Выражения (EXP)
Представлен в R2019b

[1] Данное программное обеспечение было создано компанией MathWorks и включает в себя следующие компоненты: «Веб-сайт SEI CERT-C», © 2017 Университет Карнеги-Меллон, веб-сайт SEI CERT-C + + © 2017 Университет Карнеги-Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги-Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги-Меллон, со специальным разрешением от его Института программного обеспечения.

ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ МЕЛЛОНА И/ИЛИ ЕГО ПРОГРАММНОГО ИНЖЕНЕРНОГО ИНСТИТУТА, СОДЕРЖАЩИЙСЯ В НАСТОЯЩЕМ ДОКУМЕНТЕ, ПОСТАВЛЯЕТСЯ КАК ЕСТЬ. УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ, ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, В ОТНОШЕНИИ ЛЮБЫХ ВОПРОСОВ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ГАРАНТИИ ПРИГОДНОСТИ ДЛЯ ЦЕЛЕЙ ИЛИ ТОВАРНОЙ ПРИГОДНОСТИ, ИСКЛЮЧИТЕЛЬНОСТИ ИЛИ РЕЗУЛЬТАТОВ, ПОЛУЧЕННЫХ ОТ ИСПОЛЬЗОВАНИЯ УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ В ОТНОШЕНИИ СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКИХ ПРАВ.

Данное программное обеспечение и связанная с ним документация не были рассмотрены и не одобрены Университетом Карнеги-Меллона или его Институтом разработки программного обеспечения.