Да: это может (иногда) существенно влиять на выходные размеры.
Если ваши лямбда-выражения отличаются друг от друга каким-либо образом, они будут генерировать разный код, и компилятор, скорее всего, не сможет объединить идентичные части. (Встраивание делает это намного сложнее.)
На первый взгляд это не кажется чем-то большим, пока вы не заметите:
Когда вы используете их внутри шаблонных функций, таких как std::sort
, компилятор генерирует новый код для каждого strong> другая лямбда.
Это может непропорционально увеличить размер кода.
bind
, однако, обычно более устойчив к таким изменениям (хотя и не застрахован от них).
Чтобы проиллюстрировать, что я имею в виду...
- Возьмите приведенный ниже пример, скомпилируйте его с помощью GCC (или Visual C++) и обратите внимание на размер выходного двоичного файла.
- Попробуйте изменить
if (false)
на if (true)
и посмотрите, как изменился размер выходного двоичного файла.
- Повторите #1 и #2 после того, как закомментируете все, кроме одного из
stable_sort
в каждой части.
Обратите внимание, что в первый раз лямбда-выражения C++11 немного меньше; после этого их размер увеличивается после каждого использования (около 3,3 КБ кода для каждой сортировки с VC++, аналогично GCC), тогда как двоичные файлы на основе boost::lambda
практически не меняют свой размер (для меня он остается прежним, когда включены все четыре с точностью до полукилобайта).
#include <algorithm>
#include <string>
#include <vector>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp> // can also use boost::phoenix
using namespace boost::lambda;
struct Foo { std::string w, x, y, z; };
int main()
{
std::vector<Foo> v1;
std::vector<size_t> v2;
for (size_t j = 0; j < 5; j++) { v1.push_back(Foo()); }
for (size_t j = 0; j < v1.size(); j++) { v2.push_back(j); }
if (true)
{
std::stable_sort(v2.begin(), v2.end(), bind(&Foo::w, var(v1)[_1]) < bind(&Foo::w, var(v1)[_2]));
std::stable_sort(v2.begin(), v2.end(), bind(&Foo::x, var(v1)[_1]) < bind(&Foo::x, var(v1)[_2]));
std::stable_sort(v2.begin(), v2.end(), bind(&Foo::y, var(v1)[_1]) < bind(&Foo::y, var(v1)[_2]));
std::stable_sort(v2.begin(), v2.end(), bind(&Foo::z, var(v1)[_1]) < bind(&Foo::z, var(v1)[_2]));
}
else
{
std::stable_sort(v2.begin(), v2.end(), [&](size_t i, size_t j) { return v1[i].w < v1[j].w; });
std::stable_sort(v2.begin(), v2.end(), [&](size_t i, size_t j) { return v1[i].x < v1[j].x; });
std::stable_sort(v2.begin(), v2.end(), [&](size_t i, size_t j) { return v1[i].y < v1[j].y; });
std::stable_sort(v2.begin(), v2.end(), [&](size_t i, size_t j) { return v1[i].z < v1[j].z; });
}
}
Обратите внимание, что это обмен размера на скорость; если вы находитесь в очень очень тесном цикле, он может включать дополнительную переменную (поскольку теперь он использует указатели на члены).
Однако это ничего не имеет ничего общего с накладными расходами std::function
(которые являются виртуальным вызовом), и даже это во многих случаях не поддается измерению, так что это не должно вызывать беспокойства.
person
user541686
schedule
21.08.2012
bind
. Но я разместил этот вопрос (и ответ), чтобы указать, что даже если вы находитесь в ситуации, когда они как читаемы, так и пригодны для использования (т.е. даже если вы не нужен полиморфизм, и даже если удобочитаемость не является проблемой), все же есть причины выбратьbind
. - person user541686   schedule 22.08.2012