Форум программистов, компьютерный форум, киберфорум
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
kquick
6 / 6 / 5
Регистрация: 15.05.2014
Сообщений: 102
#1

Прокомментировать код функций, генерирующих другие функции (лямбды) - C++

05.01.2016, 21:49. Просмотров 223. Ответов 3
Метки нет (Все метки)

В функциональном программировании функции могут возвращать другие функции.

Корректно ли делать это в C++ так, как показано ниже? Какие могут быть проблемы?
Пример 1:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <functional>
 
std::function<int(int)> gen_fun(int n) {
    return [&n](int x) { return x*n; };
}
 
int main() {
    std::function<int(int)> f = gen_fun(5);
    std::cout << f(1) << std::endl;
    std::cout << f(2) << std::endl;
    std::cout << f(3) << std::endl;
}
Пример 2:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <functional>
 
std::function<int()> gen_clo() {
    static int n = 1;
    return [=]() { return n++; };
}
 
int main() {
    std::function<int()> f1 = gen_clo();
    std::function<int()> f2 = gen_clo();
    std::cout << f1() << std::endl;
    std::cout << f1() << std::endl;
    std::cout << f2() << std::endl;
}
Во втором примере в замыканиях разделяемая общая n. Как генерировать независимые n при каждом создании такого замыкания?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
05.01.2016, 21:49
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Прокомментировать код функций, генерирующих другие функции (лямбды) (C++):

Не применяя библиотечных функций, напишите код функции - C++
Не применяя библиотечных функций, напишите код функции для вычисления чисел типа int и double в целую степень n. Напишите программу, в...

Прокомментировать код - C++
Добрый день. Для тех у кого времени хватает и нечем заняться, просьба прокомментировать след. код : // A simple computerized telephone...

Прокомментировать код - C++
#pragma hdrstop #include &lt;conio.h&gt; #include &lt;cmath&gt; #include &lt;iostream&gt; using namespace std; int main() { int k =...

Прокомментировать код - C++
Прокомментируйте, пожалуйста, код. Не совсем понимаю, что происходит внутри функции rec. int a, b, k, n; void rec(int x, int...

Прокомментировать код - C++
Имеется небольшая часть программки, вот в собственно в чем вопрос &quot;коментарии&quot; void v(double*a, int &amp;n , int l,double d) // int...

Прокомментировать код - C++
#include &lt;iostream&gt; #include &lt;string&gt; using namespace std; void sort(int* m, int n); struct Notebook { int ram; ...

3
Melg
538 / 159 / 64
Регистрация: 23.09.2013
Сообщений: 314
05.01.2016, 22:01 #2
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
kquick, С Новым Годом Вас!
Проблемы с первым вариантом связаны с тем, что Вы захватываете в лямде по ссылке значение переменной n, область видимости которой ограничена самой функцией gen_fun. Таким образом после того как Вы возвращаете функцию из gen_fun - один из захваченных по ссылке объектов перестает существовать. Это приводит к тому, что память, выделенная под данный объект может быть использована под другие объекты. Данная проблема эквивалентна попытке возврата ссылки на объект локальный для функции.
Данная ситуация приводит к неопределенному поведению. Т.е. программа в этом случае может делать всё, что угодно. Например, вести себя "якобы" правильно, и делать то что Вы ожидаете:
http://ideone.com/Ga0sbZ
А может и нет:
https://coderpad.io/XW22R4RH

на случай, если кто-то удалит код программы, там получается вывод :
9:47pm - Melg running 13 lines of C++
5
0
0
Согласитесь, один и тот же текст программы, дающий разное поведение из-за компиляции двумя разными компиляторами, поддерживающими один и тот же стандарт (или с разными флагами) - не лучшая ситуация.

Пример 2 не так проблематичен. В данном случае вы просто вводите статическую переменную, значение которой будет инициализировано при первом вызове. Проблема данного кода состоит в том, что полученная из gen_clo функция будет иметь скрытую зависимость от глобального состояния. Таким образом тривиальная проверка:
std::function<int()> f = gen_clo();
assert(f(), f()); будет проваливаться.
Кроме того данный код не является потоко-безопасным.
Насколько мне известно, в программировании имеется стремление к написанию кода, в котором любые зависимости между частями программы выражены в явной форме. Это позволяет проще думать о таком коде, проще его отлаживать и тестировать.

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

Добавлено через 1 минуту
Зы. Я отвечал на первую постановку вопроса:
Корректно ли делать это в C++ так, как показано ниже? Какие могут быть проблемы?
3
anti-k
227 / 75 / 23
Регистрация: 17.07.2015
Сообщений: 774
Завершенные тесты: 1
05.01.2016, 22:04 #3
Цитата Сообщение от kquick Посмотреть сообщение
std::function<int(int)> gen_fun(int&Melg, n) {
* * return [&n](int x) { return x*n; };
}
Вот так будет ок?
0
Melg
538 / 159 / 64
Регистрация: 23.09.2013
Сообщений: 314
05.01.2016, 22:06 #4
Лучший ответ Сообщение было отмечено автором темы, экспертом или модератором как ответ
anti-k, Пример иллюстрирующий возможную реализацию корректного захвата:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <functional>
 
std::function<int(int)> gen_fun(int n) {
    return [&n](int x) { return x*n; };
}
 
std::function<int(int)> right_gen_fun(const int &n) {
    return [&n](int x) { return x*n; };
}
 
void TestDefault() {
    std::function<int(int)> f = gen_fun(5);
    std::cout << f(1) << std::endl;
    std::cout << f(2) << std::endl;
    std::cout << f(3) << std::endl;
}
 
void TestRight() {
    std::function<int(int)> f = right_gen_fun(5);
    int value = 0;
    std::cout << f(++value) << std::endl;
    std::cout << f(++value) << std::endl;
    std::cout << f(++value) << std::endl;
}
 
int main() {
  TestDefault();
  TestRight();
}
Пруф работоспособности:
http://ideone.com/XlApi6
2
05.01.2016, 22:06
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
05.01.2016, 22:06
Привет! Вот еще темы с ответами:

Прокомментировать код - C++
Как это работает? #include &lt;QDebug&gt; int main() { int mass; mass = 1; mass = 2;

Прокомментировать код - C++
#include &lt;iostream.h&gt; #include &lt;conio.h&gt; #include &lt;stdio.h&gt; #include &lt;iomanip.h&gt; #include &lt;stdlib.h&gt; int main() { int...

Прокомментировать код - C++
нужно описать что делают строки готовой программы #include &lt;iostream&gt; #include &lt;string&gt; #include &lt;cmath&gt; using namespace std; ...

Прокомментировать код - C++
Здравствуйте! Пожалуйста, как можно яснее откомментируйте коды программ, очень нужно для понимания, чтобы разобраться.. пожалуйста.. 1...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru