CERT C++: EXP61-CPP

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

Описание

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

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

Реализация Polyspace

Эта проверка проверяет, что объект покидает возможности через выражение лямбды.

Примеры

расширить все

Проблема

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

Риск

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

Например, рассмотрим эту функцию 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 Университет Карнеги Меллон, с специального разрешения от его Института программной инженерии.

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

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