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

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

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

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

17.03.2014, 13:05. Просмотров 1397. Ответов 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;
}
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
17.03.2014, 13:05     Какова польза лямбда выражений
Посмотрите здесь:

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

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

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

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

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

Max_element с лямбда-функцией - C++
Интереса ради решил попробовать такую конструкцию string s; getline(cin,s); auto ma=max_element(s.begin(),s.end(),(string...

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

После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 17:59  [ТС]     Какова польза лямбда выражений #21
а теперь так:
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/*
 * 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 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;
    }
}
 
 
class A {
public:
    A()
    :
        i(0)
    {
    }
 
   ~A() {
    }
 
    void increase() {
        i++;
    }
 
private:
    int i;
};
 
 
void testLambdaVsFor() {
    const size_t    count = 100000000;
    vector<A>       data;
    timeval         stopwatch_time;
 
    cout << "data pushback " << endl;
    {
        cout << "  lambda:" << endl;
        stopwatch_time = getCurrentTime();
        data.resize(count);
        generate(data.begin(), data.end(), []() {return A();} );
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    data.clear();
 
    {
        cout << "  lambda back_inserter:" << endl;
        stopwatch_time = getCurrentTime();
        generate_n(back_inserter(data), count, []() {return A();} );
        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(A());
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    cout << "data modify" << endl;
    {
        cout << "  lambda:" << endl;
        stopwatch_time = getCurrentTime();
        std::for_each(data.begin(), data.end(), [](A &a) {a.increase();} );
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "  for iterator:" << endl;
        stopwatch_time = getCurrentTime();
        for (auto i = data.begin(); i != data.end(); i++)
            i->increase();
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "  for counter:" << endl;
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < data.size(); i++)
            data[i].increase();
        cout << "  " << getElapsedMicrosecond(stopwatch_time) << endl;
    }
}
 
 
int main() {
    testLambdaVsFor();
 
    return 0;
}

здесь у меня сомнения на счет
C++
1
std::for_each(data.begin(), data.end(), [](A &a) {a.increase();} );
того что "а" изменяется по ссылке

вывод:
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
data pushback 
  lambda:
  204060
  lambda back_inserter:
  146439
  for counter:
  195790
data modify
  lambda:
  41585
  for iterator:
  40639
  for counter:
  40518
Добавлено через 1 час 21 минуту
взгляните еще раз на тест, все ли верно, добавил еще конструкторы перемещения:

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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/*
 * 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;
}
 
 
class A {
public:
    A()
    :
        i(0)
    {
    }
 
   ~A() {
    }
 
    void increase() {
        i++;
    }
 
private:
    int i;
};
 
 
void testLambdaVsForPointer() {
    const size_t    count = 10000000;
    vector<A*>      data;
    timeval         stopwatch_time;
 
    cout << "test lambda vs for dynamic objects:" << endl;
    cout << "  data pushback " << endl;
    {
        cout << "    lambda:                       ";
        stopwatch_time = getCurrentTime();
        data.resize(count);
        generate(data.begin(), data.end(), []() -> A* {return new A;} );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    std::for_each(data.begin(), data.end(), [](A *a) {delete a;} );
    data.clear();
 
    {
        cout << "    lambda back_inserter:         ";
        stopwatch_time = getCurrentTime();
        generate_n(back_inserter(data), count, []() -> A* {return new A();} );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    std::for_each(data.begin(), data.end(), [](A *a) {delete a;} );
    data.clear();
 
    {
        cout << "    for counter:                  ";
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < count; i++)
            data.push_back(new A());
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    cout << "  data modify" << endl;
    {
        cout << "    lambda:                       ";
        stopwatch_time = getCurrentTime();
        std::for_each(data.begin(), data.end(), [](A *a) {a->increase();} );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "    for iterator:                 ";
        stopwatch_time = getCurrentTime();
        for (auto i = data.begin(); i != data.end(); i++)
            (*i)->increase();
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "    for counter:                  ";
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < data.size(); i++)
            data[i]->increase();
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    std::for_each(data.begin(), data.end(), [](A *a) {delete a;} );
}
 
 
void testLambdaVsFor() {
    const size_t    count = 10000000;
    vector<A>       data;
    timeval         stopwatch_time;
 
    cout << "test lambda vs for static objects:" << endl;
    cout << "  data pushback " << endl;
    {
        cout << "    lambda:                       ";
        stopwatch_time = getCurrentTime();
        data.resize(count);
        generate(data.begin(), data.end(), []() {return A();} );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    data.clear();
 
    {
        cout << "    lambda back_inserter:         ";
        stopwatch_time = getCurrentTime();
        generate_n(back_inserter(data), count, []() {return A();} );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    data.clear();
 
    {
        cout << "    for counter:                  ";
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < count; i++)
            data.push_back(A());
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    cout << "  data modify" << endl;
    {
        cout << "    lambda:                       ";
        stopwatch_time = getCurrentTime();
        std::for_each(data.begin(), data.end(), [](A &a) {a.increase();} );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "    for iterator:                 ";
        stopwatch_time = getCurrentTime();
        for (auto i = data.begin(); i != data.end(); i++)
            i->increase();
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "    for counter:                  ";
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < data.size(); i++)
            data[i].increase();
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
}
 
 
vector<A> copy(const size_t &count) {
    vector<A>   data(count);
    return      data;
}
 
 
vector<A> move(const size_t &count) {
    vector<A>   data(count);
    return      move(data);
}
 
 
void testMoveVsCopy() {
    cout << "test move vs copy:" << endl;
 
    const size_t    size    = 10;
    const uint      count   = 100000000;
    vector<A>       data(size);
    timeval         stopwatch_time;
 
    {
        cout << "    copy:                         ";
        stopwatch_time = getCurrentTime();
        for (uint i = 0; i < count; i++)
            data = copy(size);
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
 
    {
        cout << "    move:                         ";
        stopwatch_time = getCurrentTime();
        for (uint i = 0; i < count; i++)
            data = move(size);
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
}
 
 
int main() {
    testLambdaVsForPointer();
    testLambdaVsFor();
    testMoveVsCopy();
 
    return 0;
}

вывод:
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
test lambda vs for dynamic objects:
  data pushback 
    lambda:                       357995
    lambda back_inserter:         179733
    for counter:                  181910
  data modify
    lambda:                       36126
    for iterator:                 36224
    for counter:                  36146
test lambda vs for static objects:
  data pushback 
    lambda:                       49147
    lambda back_inserter:         17607
    for counter:                  20895
  data modify
    lambda:                       4429
    for iterator:                 4041
    for counter:                  4040
test move vs copy:
    copy:                         3108588
    move:                         3115485
Croessmah
Модератор
Эксперт CЭксперт С++
12979 / 7291 / 812
Регистрация: 27.09.2012
Сообщений: 18,007
Записей в блоге: 3
Завершенные тесты: 1
17.03.2014, 18:04     Какова польза лямбда выражений #22
C++
1
2
3
4
vector<A> copy(const size_t &count) {
    vector<A>   data(count);
    return      data;//<-- кто Вам сказал что здесь будет копирование?
}
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 18:44  [ТС]     Какова польза лямбда выражений #23
поменял код на
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const size_t    size    = 10;
vector<A> input_data(size);
 
 
vector<A> copy(const size_t &count) {
    vector<A> result;
    result.assign(input_data.begin(), input_data.end());
    return result;
}
 
 
vector<A> move(const size_t &count) {
    return move(input_data);
}

стало:
Bash
1
2
3
test move vs copy:
    copy:                         4202579
    move:                         182200
но здесь мне пришлось явно указать копирование

Цитата Сообщение от Croessmah Посмотреть сообщение
return * * *data;//<-- кто Вам сказал что здесь будет копирование?
по идее здесь компилятор оптимизирует копирование временного объекта в перемещение, т.е. move не обязательно писать

Добавлено через 7 минут
теперь точно копирование, окончательный код:

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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/*
 * 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;
}
 
 
class A {
public:
    A()
    :
        i(0)
    {
    }
 
   ~A() {
    }
 
    void increase() {
        i++;
    }
 
private:
    int i;
};
 
 
void testLambdaVsForPointer() {
    const size_t    count = 10000000;
    vector<A*>      data;
    timeval         stopwatch_time;
 
    cout << "test lambda vs for dynamic objects:" << endl;
    cout << "  data pushback " << endl;
    {
        cout << "    lambda:                       ";
        stopwatch_time = getCurrentTime();
        data.resize(count);
        generate(data.begin(), data.end(), []() -> A* {return new A;} );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    std::for_each(data.begin(), data.end(), [](A *a) {delete a;} );
    data.clear();
 
    {
        cout << "    lambda back_inserter:         ";
        stopwatch_time = getCurrentTime();
        generate_n(back_inserter(data), count, []() -> A* {return new A();} );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    std::for_each(data.begin(), data.end(), [](A *a) {delete a;} );
    data.clear();
 
    {
        cout << "    for counter:                  ";
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < count; i++)
            data.push_back(new A());
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    cout << "  data modify" << endl;
    {
        cout << "    lambda:                       ";
        stopwatch_time = getCurrentTime();
        std::for_each(data.begin(), data.end(), [](A *a) {a->increase();} );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "    for iterator:                 ";
        stopwatch_time = getCurrentTime();
        for (auto i = data.begin(); i != data.end(); i++)
            (*i)->increase();
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "    for counter:                  ";
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < data.size(); i++)
            data[i]->increase();
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    std::for_each(data.begin(), data.end(), [](A *a) {delete a;} );
}
 
 
void testLambdaVsFor() {
    const size_t    count = 10000000;
    vector<A>       data;
    timeval         stopwatch_time;
 
    cout << "test lambda vs for static objects:" << endl;
    cout << "  data pushback " << endl;
    {
        cout << "    lambda:                       ";
        stopwatch_time = getCurrentTime();
        data.resize(count);
        generate(data.begin(), data.end(), []() {return A();} );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    data.clear();
 
    {
        cout << "    lambda back_inserter:         ";
        stopwatch_time = getCurrentTime();
        generate_n(back_inserter(data), count, []() {return A();} );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    data.clear();
 
    {
        cout << "    for counter:                  ";
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < count; i++)
            data.push_back(A());
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    cout << "  data modify" << endl;
    {
        cout << "    lambda:                       ";
        stopwatch_time = getCurrentTime();
        std::for_each(data.begin(), data.end(), [](A &a) {a.increase();} );
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "    for iterator:                 ";
        stopwatch_time = getCurrentTime();
        for (auto i = data.begin(); i != data.end(); i++)
            i->increase();
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
    {
        cout << "    for counter:                  ";
        stopwatch_time = getCurrentTime();
        for (size_t i = 0; i < data.size(); i++)
            data[i].increase();
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
}
 
 
const size_t    size    = 10;
vector<A> input_data(size);
 
 
vector<A> copy(const size_t &count) {
    return input_data;
}
 
 
vector<A> move(const size_t &count) {
    return move(input_data);
}
 
 
void testMoveVsCopy() {
    cout << "test move vs copy:" << endl;
 
    const uint      count   = 100000000;
    vector<A>       data(size);
    timeval         stopwatch_time;
 
    {
        cout << "    copy:                         ";
        stopwatch_time = getCurrentTime();
        for (uint i = 0; i < count; i++)
            data = copy(size);
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
 
 
    {
        cout << "    move:                         ";
        stopwatch_time = getCurrentTime();
        for (uint i = 0; i < count; i++)
            data = move(size);
        cout << getElapsedMicrosecond(stopwatch_time) << endl;
    }
}
 
 
int main() {
    testLambdaVsForPointer();
    testLambdaVsFor();
    testMoveVsCopy();
 
    return 0;
}

вывод:
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
test "lambda" vs "for", dynamic objects:
  data pushback 
    lambda:                       350438
    lambda back_inserter:         171635
    for counter:                  172581
  data modify
    lambda:                       35920
    for iterator:                 35974
    for counter:                  36039
test "lambda" vs "for", static objects:
  data pushback 
    lambda:                       50632
    lambda back_inserter:         18197
    for counter:                  20828
  data modify
    lambda:                       4016
    for iterator:                 4076
    for counter:                  4039
test constructor "move" vs "copy":
    copy:                         3562513
    move:                         177599

временные локальные переменные в функциях при возврате значения оптимизируются в место конструктора копирования используется конструктор перемещения.

Добавлено через 5 минут
Ну и, наконец, тест показывает что все три способа перебора массива примерно одинаковы по скорости, тогда в чем сахар синтаксиса лямбда выражений ?
DrOffset
6909 / 4102 / 933
Регистрация: 30.01.2014
Сообщений: 6,893
17.03.2014, 19:02     Какова польза лямбда выражений #24
Цитата Сообщение от volodja- Посмотреть сообщение
одинаковы по скорости
Цитата Сообщение от volodja- Посмотреть сообщение
сахар синтаксиса лямбда выражений
Откуда такая тяга сравнивать несравниваемое?
Сахар в том, что не надо писать отдельный класс для функтора. Если нужен захват локальных переменных, то не надо заботиться о "протаскивании" их в этот класс. И не надо думать о том, что имя очередного написанного функтора совпадет с одним из уже существующих. Это и называется синтаксический сахар, проще говоря, когда надо писать меньше кода [по сравнению с аналогичным вариантом].
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 19:17  [ТС]     Какова польза лямбда выражений #25
данный исходник показывает что лямбда даже немножко более громоздки чем циклы
Croessmah
Модератор
Эксперт CЭксперт С++
12979 / 7291 / 812
Регистрация: 27.09.2012
Сообщений: 18,007
Записей в блоге: 3
Завершенные тесты: 1
17.03.2014, 19:26     Какова польза лямбда выражений #26
Цитата Сообщение от volodja- Посмотреть сообщение
данный исходник показывает что лямбда даже немножко более громоздки чем циклы
a + b короче чем Ваш цикл, пользуйтесь!
Можете еще циклы с диррективами препроцессора сравнить или принтер с клавиатурой - а че, оба же печатают
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
18.03.2014, 08:30  [ТС]     Какова польза лямбда выражений #27
тем не менее вопрос по лямбда остается открытым ...
DrOffset
6909 / 4102 / 933
Регистрация: 30.01.2014
Сообщений: 6,893
18.03.2014, 08:42     Какова польза лямбда выражений #28
volodja-, какой вопрос-то?
Нет никакого смысла сравнивать функторы с голыми циклами в общем случае. Если у тебя такая задача, где подходит обычный перебор в цикле, то надо использовать его. Если у тебя задача, где нужно абстрагироваться от конкретного действия, то лучше подходят лямбды. Можно сравнивать только так: что лучше решает конкретную задачу. Просто всегда по-умолчанию фигачить все в теле цикла, или просто всегда по-умолчанию фигачить алгоритмы с лямбдами - неправильно.
И как уже говорилось не раз, лямбды это функторы, то есть их используют не только для перебора чего-то в цикле. У них применение гораздо более широкое. Исходя из этого, вопрос "что лучше циклы или лямбды" не имеет ответа в такой формулировке.
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
18.03.2014, 10:27  [ТС]     Какова польза лямбда выражений #29
можете привести пример когда уместно использовать лямбда и не уместно циклы и наоборот ?
0x10
2459 / 1631 / 238
Регистрация: 24.11.2012
Сообщений: 4,009
18.03.2014, 10:44     Какова польза лямбда выражений #30
Цитата Сообщение от volodja- Посмотреть сообщение
можете привести пример когда уместно использовать лямбда и не уместно циклы и наоборот ?
Вам тут в каждом посте одно и то же повторяют: эти вещи не являются взаимозаменяемыми, поскольку они вообще про разное.
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
18.03.2014, 12:08  [ТС]     Какова польза лямбда выражений #31
Цитата Сообщение от 0x10 Посмотреть сообщение
Вам тут в каждом посте одно и то же повторяют: эти вещи не являются взаимозаменяемыми, поскольку они вообще про разное.
В таком случае приведите два совершенно не взаимозаменяемых примера, чтоб почувствовать так сказать разницу .
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
18.03.2014, 12:51     Какова польза лямбда выражений
Еще ссылки по теме:

Интерфейсная ссылка vs лямбда - C++
Добрый день, если надо, чтобы класс А вслучаи определённого евента сообщил об этом нужного другому классу Б это можно сделать...

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

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

лямбда как параметр функции - C++
здравствуйте, есть код: template&lt;typename Container, typename...Args&gt; void fafa(Container&amp;&amp; c, std::function&lt;Args...&gt; f) { ...

Лямбда-выражение, allocator + destroy - C++
Подскажите в чем ошибка пожалуйста( отказывается выполнять функцию destroy: std::allocator&lt;std::string&gt;&amp; newAlloc = alloc; ...


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

Или воспользуйтесь поиском по форуму:
0x10
2459 / 1631 / 238
Регистрация: 24.11.2012
Сообщений: 4,009
18.03.2014, 12:51     Какова польза лямбда выражений #32
Цитата Сообщение от volodja- Посмотреть сообщение
В таком случае приведите два совершенно не взаимозаменяемых примера, чтоб почувствовать так сказать разницу
Вы можете вообще выбросить из кода все функции, классы, циклы. Написать одну портянку в main - даже будет работать. Другое дело, что поддерживать это будет невозможно.
Суть в том, что одни конструкции можно заменять другими. Просто в Вашем понимании лямбда эквивалентна циклу.

Я для порядка распишу цепочку изменений в коде, но уже и не рассчитываю, что будет услышано именно то, что я пытаюсь сказать.

Задача такая: пусть у нас есть контейнер структур одного типа, который нужно преобразовать в контейнер структур другого типа. Например, контейнер пар целых чисел в контейнер структур с двумя полями.

Пусть в первом приближении код выглядит вот так:
Кликните здесь для просмотра всего текста
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
#include <algorithm>
#include <iostream>
 
struct Point
{
    Point(int x_, int y_) : x(x_), y(y_) {}
 
    int x;
    int y;
};
 
typedef std::vector<Point> PointContainer;
 
typedef std::pair<int, int> Pair;
typedef std::vector<Pair> PairContainer;
 
int main()
{
    PairContainer source = {{1, 2}, {3, 4}, {5, 6}};
    PointContainer dest;
 
    for (size_t i = 0; i < source.size(); ++i)
    {
        dest.emplace_back(source[i].first, source[i].second);
    }
 
    for (size_t i = 0; i < dest.size(); ++i)
    {
        std::cout << dest[i].x << " " << dest[i].y << std::endl;
    }
 
    return 0;
}


Это рабочий код, имеющий право на жизнь. Но есть два недостатка.
1. Он недостаточно универсален. Код предполагает, что мы работаем с контейнером, для которого возможен произвольный доступ к элементам. При необходимости заменить std::vector на std::list этот код придется переписывать.
2. Код читается на очень низком уровне. "Для i от 0 до размера контейрера взять i-тый элемент и разместить его в другом контейнере".

Первый недостаток устраняется использованием итераторов. Или даже перескочим через них и воспользуемся циклом foreach.
Кликните здесь для просмотра всего текста
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
#include <algorithm>
#include <iostream>
 
struct Point
{
    Point(int x_, int y_) : x(x_), y(y_) {}
 
    int x;
    int y;
};
 
typedef std::vector<Point> PointContainer;
 
typedef std::pair<int, int> Pair;
typedef std::vector<Pair> PairContainer;
 
int main()
{
    PairContainer source = {{1, 2}, {3, 4}, {5, 6}};
    PointContainer dest;
 
    for (const auto& item : source)
    {
        dest.emplace_back(item.first, item.second);
    }
 
    return 0;
}

Код стал сильно проще. Он тоже вполне рабочий и правильный. Читается значительно проще: для каждого элемента из контейнера разместить в другой конрейнер новый элемент, сконструировав его на основе текущего. (Скомкано написал, просто лень расписывать)

Но в данном случае это простая операция, которая уже реализована стандартным алгоритмом std::transform.
Кликните здесь для просмотра всего текста
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
#include <algorithm>
#include <iostream>
 
struct Point
{
    Point(int x_, int y_) : x(x_), y(y_) {}
 
    int x;
    int y;
};
 
typedef std::vector<Point> PointContainer;
 
typedef std::pair<int, int> Pair;
typedef std::vector<Pair> PairContainer;
 
struct PairToPoint
{
    Point operator()(const Pair& p) const
    {
        return {p.first, p.second};
    }
};
 
int main()
{
    PairContainer source = {{1, 2}, {3, 4}, {5, 6}};
    PointContainer dest;
 
    std::transform(source.begin(), source.end(), std::back_inserter(dest),
        PairToPoint());
 
    return 0;
}

Проделал я эту последовательность, чтобы показать: мы цикл заменили на вызов функции. Не на лямбду, не на функтор.

Недостато кода в том, что нам пришлось для простого преобразования создать новую структуру, что само по себе занимает дополнительное место. И вот уже функтор мы можем заменить на лямбду.
Кликните здесь для просмотра всего текста
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
#include <algorithm>
#include <iostream>
 
struct Point
{
    Point(int x_, int y_) : x(x_), y(y_) {}
 
    int x;
    int y;
};
 
typedef std::vector<Point> PointContainer;
 
typedef std::pair<int, int> Pair;
typedef std::vector<Pair> PairContainer;
 
int main()
{
    PairContainer source = {{1, 2}, {3, 4}, {5, 6}};
    PointContainer dest;
 
    std::transform(source.begin(), source.end(), std::back_inserter(dest),
        [](const Pair& p){ return Point{p.first, p.second}; });
 
    return 0;
}


Что лучше - foreach или использование функции - решать можно по ситуации.
Что предпочесть - написание функтора или лямбды - часто зависит от объема тела. Для однострочников проще использовать лямбду.

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

Ну и приведу еще такое извращение. Пример искусственный, но нечто подобное случалось видеть в коде.
Была потребность написать свою функцию уничтожения объекта, чтобы перед вызовом деструктора был вызван еще один метод. Класс был библиотечный, поэтому по сути нужно было написать свою обертку с инициализацией в конструкторе и корректным уничтожением в деструкторе. Поскольку было влом писать свой класс, переиспользовали std::shared_ptr с кастомной функцией удаления. Профит - одна строчка для разового объекта вместо написания полноценного класса. Увлекаться таким не стоит, но опыт забавный.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <memory>
 
struct Data
{
    void Destroy()
    {
        std::cout << "Destroy" << std::endl;
    }
};
 
int main()
{
    {
        std::shared_ptr<Data> data(new Data(),
            [](Data* data) { data->Destroy(); });
    }
 
    return 0;
}
Yandex
Объявления
18.03.2014, 12:51     Какова польза лямбда выражений
Ответ Создать тему
Опции темы

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