2016-05-08 2 views
11

К сожалению, это многословно вопрос, но позвольте мне разбить его:Какова продолжительность жизни цели указателя на функцию, указывающая на лямбда?

ли C++ стандарт гарантирует, что:

void (*Ptr)(void) = [] {}; 
return Ptr; 

по-прежнему будет определено поведение?

Я понимаю, что для замыкания он будет определен, потому что этот объект замыкания перемещается/копируется по значению; но, хотя я знаю, что «регулярная» функция имеет бесконечное/нет времени жизни, имеет ли цель Ptr то же самое? Или он разрушен и воссоздан с каждым экземпляром лямбды?

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

+0

Интересный вопрос. Поскольку указатель укажет на некоторый элемент * static * "invoker", у статического члена нет другого выбора, кроме как использовать какой-то фиктивный объект для вызова 'operator()' лямбды (потому что последний нестационар). Этот фиктивный код должен быть либо локальным, либо «invoker», или статическим, то есть должен работать нормально в вышеупомянутом контексте. Но я не сразу вижу эту гарантию в спецификации языка. Спецификация языка даже не постулирует существование этого фиктивного объекта. – AnT

+4

@ant Почему? Мне нужно запустить тот же код. Зачем это нужно в 'operator()'? 'operator()' можно было бы реализовать, вызвав статическую функцию, которая 'operator void (*)()()' возвращает – Yakk

+4

. Я бы хотел, чтобы все «длинные» вопросы были такими короткими –

ответ

2

лямбда-функция - это просто синтаксический сахар для реальной функции или функтора (т. Е. Объект с operator() и некоторые члены, определенные обычно во время построения). Таким образом, такая функция или метод статически определяется во время компиляции.

Хотя стандарт не может полностью указывать на точный способ реализации, как отметил @NicolBolas, кажется, что практические реализации следуют строгому указанию: лямбда без контекста может быть преобразована в простой указатель на функцию, не создавалось ни на месте, ни при вызове лямбды, ни в месте вызова. Я только что проверил его (еще раз) для gcc и clang, и я почти уверен, что MSVC делает то же самое.

Примечание: Остальное касается лямбда с контекстами, и хотя для меня это выглядит более интересным и практичным, вопрос явно касается неконкурентных лямбдов.

Контекст хранится в лямбда (подумайте о объекте-функторе с некоторыми значимыми аргументами, полученными при построении объекта). Таким образом, если вы передадите некоторые ссылки или указатели на контекст, эти ссылки и указатели (например, this) не будут автоматически продлевать время жизни их соответствующих объектов. Вот почему вы должны быть осторожны при сохранении лямбда в области, отличной от той, которая была определена.

См. Пример проблем, связанных с лямбдой и ее контекстной областью определения в этом документе resolved issue. Проверьте исправление, чтобы увидеть, что было сделано, чтобы сделать сохраненные лямбды безопасными для контекста.

+1

«Лямбда с пустым контекстом всегда превращается в анонимную статическую функцию« Что? Нет. 'Auto f = [] {}; static_assert (std :: is_same {}, "nope"); ' – Yakk

+0

Хорошо, вы правы. Но все же такая лямбда может быть назначена соответствующему указателю на функцию, как в примере для стартера темы. – user3159253

+4

Ваш второй пара, кажется, говорит о лямбдах с захватом, но вопрос OP о беззаботной лямбда –

5

Объекты имеют жизни; функции нет. Функции не живут и не умирают; они всегда существуют. Таким образом, функция не может выходить «из области видимости», и функция, на которую указывает предыдущий действительный указатель функции, исчезает. Независимо от того, откуда они берутся, указатели на функции всегда действительны.

Теперь это игнорирует динамическую нагрузку и т. Д., Но это нестандартное поведение.

Указатель функции, который вы возвращаете из лямбда, является указателем на функцию. Это не особенное или волшебное. Поэтому он ведет себя не иначе, как любой другой указатель на функцию.


Возможно ли, что в результате преобразования к мочеиспусканию (*)() указывает на то, которое вызывает функцию-член, связанный с какой-либо объект?

Это гораздо более сложный вопрос. Тот, который стандарт кажется довольно недооцененным. В стандарте указывается только:

адрес функции, которая при вызове имеет тот же эффект, что и вызов оператора вызова типа замыкания.

Что означает «такой же эффект», это вопрос. Можно утверждать, что «тот же эффект» означает выполнение того, что сделал оператор вызова функции, выполняя ту же последовательность утверждений. Можно также утверждать, что «тот же эффект» означает вызов самого объекта замыкания.

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

Ненормативный текст, по-видимому, не очень подходит по этому вопросу. Существует пример закрытия для (родовой) лямбды, в котором говорится следующее:

template<class T> auto operator()(T t) const { ... } 
template<class T> static auto lambda_call_operator_invoker(T a) { 
// forwards execution to operator()(a) and therefore has 
// the same return type deduced 
... 
} 

Комментарий в вопросе предполагает перенаправление, но это потребовало бы, что статический вызова построить новый экземпляр класса lambda, чтобы выполнить переадресацию.

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

+0

Как функции участника вписываются в это? –

+2

@ M.M: Указатели для членов - это разные вещи (и не по теме), но они по-прежнему придерживаются той же идеи. «Участники» не являются объектами. Таким образом, у них нет жизней. Указатели элементов всегда действительны. Однако вам все равно нужен объект для их вызова; этот объект может быть или не быть действительным. –

+1

Функции-члены являются по существу обычными функциями с дополнительным скрытым аргументом (это). Поэтому, как только вы загрузили программу, все функции-члены находятся на своих местах, но объектов еще нет – user3159253

Смежные вопросы