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

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

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

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++ лямбда заполнения вектора
Передача лямбда в функции C++
C++ лямбда функция
С++11 Лямбда-выражения и вывод результата C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
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
Модератор
Эксперт С++
 Аватар для Croessmah
11845 / 6824 / 771
Регистрация: 27.09.2012
Сообщений: 16,919
Записей в блоге: 2
Завершенные тесты: 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
6460 / 3834 / 885
Регистрация: 30.01.2014
Сообщений: 6,629
17.03.2014, 19:02     Какова польза лямбда выражений #24
Цитата Сообщение от volodja- Посмотреть сообщение
одинаковы по скорости
Цитата Сообщение от volodja- Посмотреть сообщение
сахар синтаксиса лямбда выражений
Откуда такая тяга сравнивать несравниваемое?
Сахар в том, что не надо писать отдельный класс для функтора. Если нужен захват локальных переменных, то не надо заботиться о "протаскивании" их в этот класс. И не надо думать о том, что имя очередного написанного функтора совпадет с одним из уже существующих. Это и называется синтаксический сахар, проще говоря, когда надо писать меньше кода [по сравнению с аналогичным вариантом].
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
17.03.2014, 19:17  [ТС]     Какова польза лямбда выражений #25
данный исходник показывает что лямбда даже немножко более громоздки чем циклы
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11845 / 6824 / 771
Регистрация: 27.09.2012
Сообщений: 16,919
Записей в блоге: 2
Завершенные тесты: 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
6460 / 3834 / 885
Регистрация: 30.01.2014
Сообщений: 6,629
18.03.2014, 08:42     Какова польза лямбда выражений #28
volodja-, какой вопрос-то?
Нет никакого смысла сравнивать функторы с голыми циклами в общем случае. Если у тебя такая задача, где подходит обычный перебор в цикле, то надо использовать его. Если у тебя задача, где нужно абстрагироваться от конкретного действия, то лучше подходят лямбды. Можно сравнивать только так: что лучше решает конкретную задачу. Просто всегда по-умолчанию фигачить все в теле цикла, или просто всегда по-умолчанию фигачить алгоритмы с лямбдами - неправильно.
И как уже говорилось не раз, лямбды это функторы, то есть их используют не только для перебора чего-то в цикле. У них применение гораздо более широкое. Исходя из этого, вопрос "что лучше циклы или лямбды" не имеет ответа в такой формулировке.
volodja-
0 / 0 / 0
Регистрация: 17.03.2014
Сообщений: 13
18.03.2014, 10:27  [ТС]     Какова польза лямбда выражений #29
можете привести пример когда уместно использовать лямбда и не уместно циклы и наоборот ?
0x10
2426 / 1598 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
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     Какова польза лямбда выражений
Еще ссылки по теме:

C++ Отладчики - какая от них польза и как ими правильно пользоваться?
Почему не работают лямбда-выражения? C++
C++ Рекурсивная лямбда

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

Или воспользуйтесь поиском по форуму:
0x10
2426 / 1598 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
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     Какова польза лямбда выражений
Ответ Создать тему
Опции темы

Текущее время: 11:12. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru