Using a lambda function in C++ with variables captured by value implies a copy of the value.
With a good compiler, and assuming we do not modify the value within the lambda function, can we hope that there will be no actual copy once the code is compiled and optimized?
For example, in the following it seems to make sense to pass new_item
as a value since it is used in read only mode.
void loadavg_file::add(loadavg_item const & new_item)
{
auto const & it(std::find_if(
f_items.begin(),
f_items.end(),
[new_item](auto const & item)
{
return (item.f_address == new_item.f_address);
}));
if(it == f_items.end())
{
f_items.push_back(it);
}
else
{
// replace existing item with new avg and timestamp
it->f_timestamp = new_item.f_timestamp;
it->f_avg = new_item.f_avg;
}
}
Will the loop be optimized out and result in absolutely no copy of new_item
?
If the copy constructor of new_item
(i.e. loadavg_item::loadavg_item(loadavg_item const&)
) has observable effects other than allocation of memory, then those effects must be observed to occur (as long as, y'know, you actually make an effort to observe them).
This is because you might be depending on those side effects occurring, and this is not a context where copy elision is allowed; copy elision is only allowed (and, latterly, mandated) when returning a value from a function. On the other hand memory allocation elision is allowed anywhere (subject to the rules in [expr.new]/10); clang is particularly good at this.
Inspecting the generated assembly does not count as observation of side effects, and nor does running the program in a debugger.
If the copy constructor of new_item
is non-inline, then the assembly of the translation unit might exhibit a call to the copy constructor as a symbol, but link-time optimization (LTO) can still elide that call if the link-time optimizer can deduce that the copy constructor has no observable side effects.
Yes, a copy is two copies (because the lambda is passed by value, its members get copied again) are required for your code.
If the entire call tree (find_if
, copy constructor, destructor, operator==
, any functions those call) consists of visible functions and the compiler choose to inline them, it is possible that further optimizations such as common-subexpression-elimination may reduce or eliminate the runtime cost of those copies.
In the process, the compiler will have to prove that
If you want to avoid the copy, don't write code asking for that copy. Or copy only the needed portion of the object, e.g.
auto const & it(std::find_if(
f_items.begin(),
f_items.end(),
[key = new_item.f_address](auto const & item)
{
return (item.f_address == key);
}));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With