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

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

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 9, средняя оценка - 4.67
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
#1

Какова польза лямбда выражений - C++

17.03.2014, 13:05. Просмотров 1497. Ответов 31
Метки нет (Все метки)

Вот набросал пример который показывает что лямбда выражения медленней простых циклов и больше кода, в чем тогда их польза ?

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
 * main.cpp
 *
 *  Created on: 31 янв. 2014 г.
 *      Author: volodja
 */
 
 
 
 
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdint.h>
#include <time.h>
#include <sys/time.h>
#include <string>
 
 
#include "stopwatch.h"
 
 
using namespace std;
 
 
timeval getCurrentTime() {
    timeval current_time;
    gettimeofday(&current_time, NULL);
    return  current_time;
}
 
 
uint64_t getElapsedMicrosecond(const timeval &stopwatch_time) {
    timeval current_time = getCurrentTime();
    return (current_time.tv_sec - stopwatch_time.tv_sec) * 1000000 + current_time.tv_usec - stopwatch_time.tv_usec;
}
 
 
vector<char> testCopy() {
    vector<char>    result;
    char            ch = 0;
 
    for (size_t i = 0; i < 10; i++) {
        ch++;
        result.push_back(ch);
    }
 
    return result;
}
 
 
vector<char>&& testMove() {
    vector<char>    result;
    char            ch = 0;
 
    for (size_t i = 0; i < 10; i++) {
        ch++;
        result.push_back(ch);
    }
 
    return move(result);
}
 
 
void testMoveVsCopy() {
    timeval         stopwatch_time;
    const size_t    count = 1000000;
    vector<char>    v;
 
    {
        cout << "copy: " << endl;
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < count; i++)
            v.push_back(testCopy()[i % 100]);
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "copy lambda: " << endl;
        stopwatch_time = getCurrentTime();
        size_t i = 0;
        generate_n(back_inserter(v), count,
            [&i]() -> char {
                i++;
                return testCopy()[i % 100];
            }
        );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "move: " << endl;
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < count; i++)
            v.push_back(testMove()[i % 100]);
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "move lambda: " << endl;
        stopwatch_time = getCurrentTime();
        size_t i = 0;
        generate_n(back_inserter(v), count,
            [&i]() -> char {
                i++;
                return testMove()[i % 100];
            }
        );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
}
 
 
//void executeLambda([](const int &i) -> double) {
//
//}
 
 
void testLambda() {
    int a = 1, b = 2;
    cout << "b = " << b << endl;
    [=, &b]{
        b = b + a;
    }();
    cout << "b = " << b << endl;
 
}
 
 
int main() {
    testMoveVsCopy();
 
    testLambda();
 
    return 0;
}
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
17.03.2014, 13:05
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Какова польза лямбда выражений (C++):

Написать парсер математических выражений с функцией упрощения этих выражений - C++
Люди, здравствуйте. Есть такая задача: написать упроститель выражений. На вход подается строка вида &quot;a*b+a*c&quot;, являющаяся корректным...

Отладчики - какая от них польза и как ими правильно пользоваться? - C++
Какую пользу несут отладчики и как ими правильно пользоваться? Нет, как его запустить я себе представляю (благо иде помогает), но что я...

Рекурсивная лямбда - C++
можно ли в лямбде сделать рекурсию? как получить имя безымянной функции? this не пашет...

Лямбда функции - C++
Всем добрый вечер! Пытаюсь ознакомиться поближе с лямбда функциями и уже возникли трудности... Просмотрела пару публикаций на эту тему и...

лямбда функция - C++
привет всем! не понимаю в чем ошибка...вот код vector&lt;string&gt; tmp_count; list&lt;string&gt; tmp_result = str; for(auto i =...

Лямбда функции - C++
Помогите пожалуйста. Написать программу демонстрирующую лямбда функцию на с++. желательно с комментариями, а то я в этом совсем ничего не...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Croessmah
Эксперт CЭксперт С++
13237 / 7509 / 847
Регистрация: 27.09.2012
Сообщений: 18,447
Записей в блоге: 3
Завершенные тесты: 1
17.03.2014, 13:09 #2
А может нужно научиться готовить их?
0
DrOffset
7155 / 4296 / 972
Регистрация: 30.01.2014
Сообщений: 7,101
17.03.2014, 13:25 #3
Фраза
Цитата Сообщение от volodja- Посмотреть сообщение
лямбда выражения медленней простых циклов
звучит как "удобрения медленнее лопаты". Абсурд не правда ли?
Сами по себе лямбда выражения - это синтаксический сахар для функторов. В С++ до этого не существовало способа сделать анонимный функтор, теперь такой способ есть, + некоторые плюшки (вроде захвата переменных). То, что ты там в своем примере заюзал стандартные алгоритмы с таким функтором и получил просадку производительности по сравнению с голым циклом, вообще никак лямбды не характеризует. Характеризует только то, что тест некорректный.
1
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 13:33  [ТС] #4
в чем не корректность теста ?
И что тогда лучше использовать в местах с простыми циклами, лямбда или циклы(итераторы) ?
Еще так к месту, конструкторы перемещения дают очень небольшой прирост производительности (в 1,04873245 раза).
Использовал самые простые конструкции, может быть лямбда можно как-то лучше приготовить ?
0
Croessmah
Эксперт CЭксперт С++
13237 / 7509 / 847
Регистрация: 27.09.2012
Сообщений: 18,447
Записей в блоге: 3
Завершенные тесты: 1
17.03.2014, 13:35 #5
Цитата Сообщение от volodja- Посмотреть сообщение
дают очень небольшой прирост производительности
ну попробуйте скопировать и переместить вектор из 100000000 объектов
0
DrOffset
7155 / 4296 / 972
Регистрация: 30.01.2014
Сообщений: 7,101
17.03.2014, 13:40 #6
Цитата Сообщение от volodja- Посмотреть сообщение
в чем не корректность теста ?
В том, что ты сравниваешь совершенно разные подходы к решению задачи. Выбрав при этом условия задачи такими, что подход с голыми циклами оказывается быстрее. Для корректности нужно было сравнивать лямбды с обычными С++ функторами (которые классы).

Цитата Сообщение от volodja- Посмотреть сообщение
И что тогда лучше использовать в местах с простыми циклами
От задачи зависит. И от целей. Озвучь конкретную задачу, будем ее рассматривать.
И еще раз скажу, лямбды - это функторы (то есть функциональные объекты, то есть объекты, которые ведут себя как функции). Ее совсем не обязательно в цикл пихать.

Цитата Сообщение от volodja- Посмотреть сообщение
конструкторы перемещения дают очень небольшой прирост производительности (в 1,04873245 раза).
А это зависит от характера данных. Нельзя так просто в общем случае утверждать.
0
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 13:41  [ТС] #7
А цикл быстрее лямбда быстрее в 1,240681149 раза (видимо за счет создания временной структуры в каждой итерации).
0
DrOffset
7155 / 4296 / 972
Регистрация: 30.01.2014
Сообщений: 7,101
17.03.2014, 13:43 #8
Цитата Сообщение от volodja- Посмотреть сообщение
А цикл быстрее лямбда
Не цикл быстрее лямбды, а цикл быстрее подхода с использованием стандартного алгоритма в этой конкретной ситуации.
1
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 13:54  [ТС] #9
Цитата Сообщение от DrOffset Посмотреть сообщение
А это зависит от характера данных. Нельзя так просто в общем случае утверждать.
В данном тесте я проверял только скорость передачи данных из локальной области видимости во внешнюю область видимости (фактически скорость return), данные не суть важно какие, просто небольшой массив байт. Не думаю что из безымянных структур можно создавать какие-то сложные конструкции, по этому предполагаю что лямда и подразумевает использование в небольших локальных конструкциях с stl.algorithm.

Добавлено через 5 минут
Цитата Сообщение от DrOffset Посмотреть сообщение
Для корректности нужно было сравнивать лямбды с обычными С++ функторами (которые классы).
Смысла нет, т.к. это одно и тоже только по разному записано, т.е. лямда при компиляции преобразуется в класс.
0
Croessmah
Эксперт CЭксперт С++
13237 / 7509 / 847
Регистрация: 27.09.2012
Сообщений: 18,447
Записей в блоге: 3
Завершенные тесты: 1
17.03.2014, 14:02 #10
Цитата Сообщение от volodja- Посмотреть сообщение
данные не суть важно какие
просто для примера:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct TEST {
   TEST ( ) {
      std::cout << "create test object" << std::endl ;
   }
   TEST ( const TEST & ) {
      std::cout << "copy test object" << std::endl ;
   }
   ~TEST ( ) {
      std::cout << "delete test object" << std::endl ;
   }
} ;
 
 
int main () {
   std::vector<TEST> vec1(5) ;
   std::cout << "BEGIN\nCopy:\n" ;
   std::vector<TEST> vec2 (vec1);
   std::cout << "Move:\n" ;
   std::vector<TEST> vec3 (std::move ( vec1 ) );
   std::cout << "END" << std::endl ;
}
Вы вообще сравниваете теплое с мягким
1
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 14:21  [ТС] #11
В моем примере оптимизация компилятора почти что уравнивает по скорости конструктор копирования и перемещения при возврате результата, по этому разница в скорости различима только для циклов и лямбда.
Вывод в консоль такой (gcc 4.7.3):

copy:
182104
copy lambda:
225933
move:
173642
move lambda:
222386
0
Croessmah
Эксперт CЭксперт С++
13237 / 7509 / 847
Регистрация: 27.09.2012
Сообщений: 18,447
Записей в блоге: 3
Завершенные тесты: 1
17.03.2014, 14:36 #12
Цитата Сообщение от volodja- Посмотреть сообщение
В моем примере оптимизация компилятора почти что уравнивает по скорости конструктор копирования и перемещения при возврате результата
В Вашем примере большая часть теста не корректна
0
Croessmah
Эксперт CЭксперт С++
13237 / 7509 / 847
Регистрация: 27.09.2012
Сообщений: 18,447
Записей в блоге: 3
Завершенные тесты: 1
17.03.2014, 14:55 #13
Чуть поменял, чтобы не было автоматических переменных в некоторых местах, которые будут не копироваться, а перемещаться
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdint.h>
#include <time.h>
#include <sys/time.h>
#include <string>
 
 
 
using namespace std;
 
 
timeval getCurrentTime() {
    timeval current_time;
    gettimeofday(&current_time, NULL);
    return  current_time;
}
 
 
uint64_t getElapsedMicrosecond(const timeval &stopwatch_time) {
    timeval current_time = getCurrentTime();
    return (current_time.tv_sec - stopwatch_time.tv_sec) * 1000000 + current_time.tv_usec - stopwatch_time.tv_usec;
}
 
 
vector<char> testCopy( vector<char> & result ) {
 
    char            ch = 0;
 
    for (size_t i = 0; i < 100000; i++) {
        ch++;
        result.push_back(ch);
    }
 
    return result;
}
 
 
vector<char> testMove(vector<char>  &result) {
    char            ch = 0;
 
    for (size_t i = 0; i < 10000; i++) {
        ch++;
        result.push_back(ch);
    }
 
    return move(result);
}
 
 
void testMoveVsCopy() {
    timeval         stopwatch_time;
    const size_t    count = 1000;
    vector<char>    v;
 
    {vector<char>    v2;
        cout << "copy: " << endl;
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < count; i++)
            v.push_back(testCopy(v2)[0]);
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {vector<char>    v2;
        cout << "copy lambda: " << endl;
        stopwatch_time = getCurrentTime();
        size_t i = 0;
        generate_n(back_inserter(v), count,
            [&i,&v2]() -> char {
                i++;
                return testCopy(v2)[0];
            }
        );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {vector<char>    v2;
        cout << "move: " << endl;
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < count; i++)
            v.push_back(testMove(v2)[0]);
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {vector<char>    v2;
        cout << "move lambda: " << endl;
        stopwatch_time = getCurrentTime();
        size_t i = 0;
        generate_n(back_inserter(v), count,
            [&i,&v2]() -> char {
                i++;
                return testMove(v2)[0];
            }
        );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
}
 
 
//void executeLambda([](const int &i) -> double) {
//
//}
 
 
void testLambda() {
    int a = 1, b = 2;
    cout << "b = " << b << endl;
    [=, &b]{
        b = b + a;
    }();
    cout << "b = " << b << endl;
 
}
 
 
int main() {
    testMoveVsCopy();
 
    testLambda();
 
    return 0;
}
Результаты:
Какова польза лямбда выражений
1
Croessmah
Эксперт CЭксперт С++
13237 / 7509 / 847
Регистрация: 27.09.2012
Сообщений: 18,447
Записей в блоге: 3
Завершенные тесты: 1
17.03.2014, 14:58 #14
Еще вопросы по эффективности перемещения имеются?
0
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 15:50  [ТС] #15
в общем разъяснил ситуацию лямбда, результат прямо противоположный:
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/*
 * main.cpp
 *
 *  Created on: 31 янв. 2014 г.
 *      Author: volodja
 */
 
 
 
 
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdint.h>
#include <time.h>
#include <sys/time.h>
#include <string>
 
 
using namespace std;
 
 
timeval getCurrentTime() {
    timeval current_time;
    gettimeofday(&current_time, NULL);
    return  current_time;
}
 
 
uint64_t getElapsedMicrosecond(const timeval &stopwatch_time) {
    timeval current_time = getCurrentTime();
    return (current_time.tv_sec - stopwatch_time.tv_sec) * 1000000 + current_time.tv_usec - stopwatch_time.tv_usec;
}
 
 
void testLambdaVsFor() {
    const size_t    count = 100000000;
    vector<char>    data;
    timeval         stopwatch_time;
    char            ch = 0;
 
    cout << "data pushback " << endl;
    {
        cout << "  lambda:" << endl;
        stopwatch_time = getCurrentTime();
        data.resize(count);
        generate(data.begin(), data.end(), [&ch]() {return ch++;} );
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    data.clear();
 
    {
        cout << "  lambda back_inserter:" << endl;
        stopwatch_time = getCurrentTime();
        generate_n(back_inserter(data), count, [&ch]() {return ch++;} );
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    data.clear();
 
    {
        cout << "  for counter:" << endl;
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < count; i++)
            data.push_back(ch++);
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    cout << "data modify" << endl;
    {
        cout << "  lambda:" << endl;
        stopwatch_time = getCurrentTime();
        std::for_each(data.begin(), data.end(), [](char &ch) {ch++;} );
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "  for iterator:" << endl;
        stopwatch_time = getCurrentTime();
        for (auto i = data.begin(); i != data.end(); i++)
            (*i)++;
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "  for counter:" << endl;
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < data.size(); i++)
            data[i]++;
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
}
 
 
int main() {
    testLambdaVsFor();
 
    return 0;
}
вывод:
data pushback
lambda:
53000
lambda back_inserter:
194452
for counter:
220521
data modify
lambda:
10275
for iterator:
61350
for counter:
120558

Добавлено через 6 минут
Цитата Сообщение от Croessmah Посмотреть сообщение
Чуть поменял, чтобы не было автоматических переменных в некоторых местах, которые будут не копироваться, а перемещаться
Скомпилено с оптимизацией без дебага ?
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
17.03.2014, 15:50
Привет! Вот еще темы с ответами:

Лямбда выражения - C++
Здрасьте) вопрос по новому стандарту, в который ввели лямбда-выражения. создаю класс, у которого есть поле data, типа map. map...

Передача лямбда в функции - C++
В чем смысл передачи лямбда выражения функции?auto square = (int x) { return x * x; }; std::cout &lt;&lt; square(16) &lt;&lt; std::endl;илиclass Foo ...

Лямбда не допускает auto - C++
Всем привет! Имеем код: #include &lt;iostream&gt; #include &lt;vector&gt; #include &lt;algorithm&gt; #include &lt;numeric&gt; int...

Лямбда, список захвата - C++
Есть ли возможность поместить в список захвата лямбды, которая находится в методе, переменную член этого класса? Точнее как это лучше...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
17.03.2014, 15:50
Ответ Создать тему
Опции темы

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