С++ 0x Lambda накладные расходы

Существуют ли какие-либо накладные расходы, связанные с использованием лямбда-выражений в C++0x (под VS2010)?
Я знаю, что использование объектов function влечет за собой накладные расходы, но я имею в виду выражения, которые передаются в STL. алгоритмы, например. Оптимизирует ли компилятор выражение, устраняя то, что кажется вызовом функции? Мне начали очень нравиться лямбда-выражения, но меня немного беспокоит штраф за скорость.

Заранее спасибо!


person Gratian Lup    schedule 10.07.2010    source источник
comment
Почему вы уверены, что использование функциональных объектов (функторов) влечет за собой накладные расходы? Их тоже можно оптимизировать! Единственный способ узнать это — построить с включенной полной оптимизацией, а затем посмотреть на сборку.   -  person EFraim    schedule 10.07.2010
comment
Когда я сказал объект функции, я имел в виду что-то вроде boost::function, моя ошибка. Я знаю, что классические объекты-функции могут быть встроены, и я хотел знать, происходит ли это и с лямбда-выражениями.   -  person Gratian Lup    schedule 10.07.2010
comment
ах хорошо, у них есть некоторые накладные расходы. Но лямбда-выражения этого не делают (если только вы не завернете их в объект std::function (не нужно использовать boost, так как это было принято в стандарте 0x).   -  person jalf    schedule 10.07.2010


Ответы (2)


Вы «знаете», что функциональные объекты несут накладные расходы? Возможно, вам следует перепроверить свои факты. :)

Обычно использование алгоритма STL с функциональным объектом не требует дополнительных затрат по сравнению с циклом, свернутым вручную. Наивному компилятору придется неоднократно вызывать operator() для функтора, но это тривиально для встраивания, и поэтому накладные расходы равны нулю.

Лямбда-выражение — это не что иное, как синтаксический сахар для функционального объекта. Код преобразуется компилятором в функциональный объект, поэтому он также не имеет накладных расходов.

person jalf    schedule 10.07.2010
comment
Эмпирически это неверно. Добавление множества экземпляров std::functions значительно увеличивает размер исполняемого файла, по крайней мере, в VS2010. Я только что провел этот тест. - person shoosh; 26.05.2011
comment
@shoosh: Итак? Добавление большого количества экземпляров std:string также влечет за собой большие накладные расходы. Но вопрос и мой ответ были не в этом. Они были о функциональных объектах и ​​лямбдах. std::function не является ни тем, ни другим. - person jalf; 30.05.2011
comment
просто чтобы уточнить, std::function является классом-оболочкой, абстракцией над всеми вызываемыми объектами, будь то указатели на функции или функторы. И это не бесплатное использование. Но если вы избегаете оболочки и просто используете функтор или лямбду напрямую, накладные расходы нулевые. - person jalf; 31.08.2012
comment
@jalf Извините за невежество .. но разве вам не нужно использовать std::function для объявления функции, которая принимает лямбду в качестве параметра? - person Tomas Andrle; 14.10.2012
comment
@TomA: не совсем так. Шаблон функции, принимающий некоторый тип T, может принимать лямбду в качестве параметра. Конечно, для функции, не являющейся шаблоном, вы должны указать фактический тип параметра, и вы не можете сделать это, если тип является лямбдой, поэтому в этом случае вы должны обернуть его в std::function или подобное. - person jalf; 14.10.2012
comment
Как сказал jalf, нет необходимости оборачивать лямбду в std::function. std::function оплачивает накладные расходы на абстракцию во время выполнения, а лямбда-выражения — нет. Предполагая, что ваши функторы оптимизированы (ctor и operator() встроены), ваши лямбда-выражения не имеют по сравнению с ними нулевых накладных расходов. Теперь, независимо от того, используете ли вы лямбда-выражения или объекты-функции напрямую, возникают накладные расходы, если вы хотите иметь возможность хранить их и вызывать во время выполнения через std::function. - person stinky472; 11.02.2013

Под капотом,

void f(char delim)
{
  std::for_each( seq.begin()
               , seq.end()
               , [=](const T& obj){std::cout << obj << delim;} );
}

примерно переводится в

class __local_class_name {
  char __delim;
public:
  __local_class_name(char delim) : __delim(delim) {}
  void operator()(const T& obj) {std::cout << obj << __delim;}
};

void f(char delim)
{
  std::for_each( seq.begin()
               , seq.end()
               , __local_class_name(delim) );
}

Как и в случае со всеми функциональными объектами, накладные расходы очень минимальны, поскольку вызов можно легко встроить.

person sbi    schedule 10.07.2010
comment
Он делает; [=] указывает, что все локальные объекты должны быть захвачены по значению. - person Dennis Zickefoose; 10.07.2010
comment
@Dennis: Только jalf добавил =, так что @Dario был прав. :( @jalf: Спасибо. Мое оправдание в том, что у меня еще не было времени поиграть с этим, так что все это напечатано понаслышке. - person sbi; 10.07.2010
comment
да, я, вероятно, должен был оставить комментарий, говоря, что я добавил это. :) Но да, [=] фиксирует все по значению. Мы могли бы также использовать [delim], чтобы конкретно зафиксировать эту переменную. Кстати, я добавил +1 к вашему ответу. :) - person jalf; 10.07.2010
comment
__local_class_name будет локальным классом в области действия функции f. C++0x позволяет использовать локальные экземпляры классов в качестве параметров для шаблонов функций (они не разрешены текущим стандартом). Также стоит отметить, что имя класса генерируется компилятором для каждой лямбды и вы не можете сами назвать тип лямбды. - person snk_kid; 10.07.2010
comment
@snk_kid: мне было интересно, будет ли этот класс локальным для функции или нет. В конце концов я решил, что, поскольку не знал, и поскольку имя в любом случае должно было быть уникальным, я бы ошибся и поместил его в область пространства имен. Можете ли вы процитировать главу и стих? Если да, то я бы пошел и перенес его. - person sbi; 10.07.2010
comment
@jalf: Нет проблем с редактированием. И я подумал, что ты проголосуешь за это, как только я тебя увижу. Тем не менее, я был первым, кто проголосовал за вас. :) - person sbi; 10.07.2010
comment
как бы вы встроили вызов? Кажется, куда бы я ни посмотрел, люди говорят, что вызов может быть легко встроен, но я не понимаю, как... Я имею в виду, что я не могу написать inline перед определением operator(), или ` я имею в виду, что все, что я пишу, это [](){return stuff;} бит, как запросить встраивание? - person Born2Smile; 11.04.2016