Предпочитайте захват по ссылке в лямбдах, которые используются локально, включая передаваемые алгоритмам
Причина
Для эффективности и корректности вы почти всегда хотите захватывать по ссылке при локальном использовании лямбды. Это включает написание или вызов параллельных алгоритмов, которые являются локальными, поскольку они присоединяются перед возвратом.
Обсуждение
Соображение об эффективности состоит в том, что большинство типов дешевле передавать по ссылке, чем по значению.
Соображение о корректности состоит в том, что многие вызовы хотят производить побочные эффекты на исходный объект на стороне вызова (см. пример ниже). Передача по значению предотвращает это.
Примечание
К сожалению, нет простого способа захватить по ссылке на const, чтобы получить эффективность локального вызова и при этом предотвратить побочные эффекты.
Пример
Здесь большой объект (сетевое сообщение) передаётся итерационному алгоритму, и копирование сообщения (которое может быть некопируемым) неэффективно и некорректно:
std::for_each(begin(sockets), end(sockets), [&message](auto& socket)
{
socket.send(message);
});
Пример
Это простой трёхэтапный параллельный конвейер. Каждый объект stage инкапсулирует рабочий поток и очередь, имеет функцию process для постановки работы в очередь, а в своём деструкторе автоматически блокирует выполнение, ожидая опустошения очереди перед завершением потока.
void send_packets(buffers& bufs)
{
stage encryptor([](buffer& b) { encrypt(b); });
stage compressor([&](buffer& b) { compress(b); encryptor.process(b); });
stage decorator([&](buffer& b) { decorate(b); compressor.process(b); });
for (auto& b : bufs) { decorator.process(b); }
} // автоматически блокирует ожидание завершения конвейера
Контроль
Помечать лямбду, которая захватывает по ссылке, но используется иначе, чем локально в области видимости функции, или передаётся функции по ссылке. (Примечание: Это правило является приближением, но оно помечает передачу по указателю, так как они с большей вероятностью сохраняются вызываемым, запись в расположение кучи через параметр, возврат лямбды и т.д. Правила времени жизни также предоставят общие правила, помечающие уходящие указатели и ссылки, включая через лямбды.)