Недетерминированное искажение с помощью лямбда-выражений в C++11

Вдохновленный убедительной лекцией Херба Саттера Не C++ вашего отца, я решил еще раз взглянуть на последнюю версию C++ с помощью Microsoft Visual Studio 2010. Меня особенно заинтересовало утверждение Херба о том, что C++ "безопасен", потому что я не слышал, как C++11 решил известную проблему восходящей функции. Насколько я могу судить, С++ 11 ничего не делает для решения этой проблемы и, следовательно, не является "безопасным".

Вы не хотите возвращать ссылку на локальную переменную, потому что локальная переменная выделена в кадре стека, который больше не будет существовать после возврата функции, и, следовательно, функция вернет висячий указатель на выделенную память, которая приведет к недетерминированному повреждению данных. Компиляторы C и C++ знают об этом и предупреждают вас, если вы пытаетесь вернуть ссылку или указатель на локальный объект. Например, эта программа:

int &bar() {
  int n=0;
  return n;
}

заставляет Visual Studio 2010 выдавать предупреждение:

warning C4172: returning address of local variable or temporary

Однако лямбда-выражения в C++11 упрощают захват локальной переменной по ссылке и возврат этой ссылки, что приводит к эквивалентному оборванному указателю. . Рассмотрим следующую функцию foo, которая возвращает лямбда-функцию, которая захватывает локальную переменную nи возвращает ее:

#include 

std::function foo(int n) {
  return [&](){return n;};
}

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

1825836376

Более того, Visual Studio 2010 не выдает никаких предупреждений.

Мне кажется, это действительно серьезный недостаток дизайна языка. Даже самый простой рефакторинг может создать кадры лямбда-перекрестного стека, незаметно вводя недетерминированное повреждение данных. Тем не менее, кажется, что информации об этой проблеме очень мало (например, поиск «upwards funarg» и C++ в StackOverflow не дает результатов). Знают ли об этом люди? Кто-нибудь работает над решением или описывает обходные пути?

5
задан ildjarn 12 April 2012 в 16:40
поделиться