Reputation: 399
I have a function that just sets a value of 1 to a struct member variable length
. In modern C++ this doesn't seem like good code style. Could this be done with a lambda?
void setEdgeLengths(Koala::AssocArray <koalaGraph::PEdge, Koala::DijkstraHeap::EdgeLabs<int >> &edgeMap, std::vector<koalaGraph::PEdge>& E)
{
for (size_t i = 0; i < E.size(); i++) {
edgeMap[E[i]].length = 1;
}
}
The reason I am asking is https://shaharmike.com/cpp/lambdas-and-functions/ suggests that the lambda will be faster than an ordinary function.
Lambdas are also awesome when it comes to performance. Because they are objects rather than pointers they can be inlined very easily by the compiler, much like functors. This means that calling a lambda many times (such as with std::sort or std::copy_if) is much better than using a global function. This is one example of where C++ is actually faster than C.
Upvotes: 0
Views: 1493
Reputation: 23691
I would consider the following code optimal (aside from given variable names):
void setEdgeLengths(Koala::AssocArray <koalaGraph::PEdge, Koala::DijkstraHeap::EdgeLabs<int >> &edgeMap, std::vector<koalaGraph::PEdge>& E)
{
for (const auto& e : E) {
edgeMap[e].length = 1;
}
}
Style (or omit) the curly braces as you like.
You can put any or all of this into arbitrarily many nested lambdas, but this is no more useful (but likely more harmful, at least in debug builds) than adding more whitespace. What you probably wanted to ask for is this:
void setEdgeLengths(Koala::AssocArray <koalaGraph::PEdge, Koala::DijkstraHeap::EdgeLabs<int >> &edgeMap, std::vector<koalaGraph::PEdge>& E)
{
std::for_each(E.begin(), E.end(), [&edgeMap](const auto& e) {
edgeMap[e].length = 1;
});
}
You no longer have a plain loop (which some advocate as good style), but I don't think the code has become any clearer. It also didn't get faster from doing this - if anything, debug performance is likely reduced slightly.
Now, the latter form does allow for parallel execution by doing
std::for_each(std::execution::parallel, E.begin(), E.end(), [&edgeMap](const auto& e) {
but this is only legal if your edgeMap
properly handles concurrent access. If it was a std::map
, operator[]
could potentially insert a new element (which is not thread-safe) so without further assumptions this would not be a legal optimization.
Upvotes: 3
Reputation: 180595
If you want to apply an operation to every element of a container then you can use std::for_each
. Since you want to use every element of E
to access edgeMap
you'll use for_each
on E
like
Koala::AssocArray <koalaGraph::PEdge, Koala::DijkstraHeap::EdgeLabs<int >> edgeMap = /* stuff */;
std::vector<koalaGraph::PEdge> E = /* stuff */;
std::for_each(E.begin(), E.end(),[&](auto const& index){ edgeMap[index].length = 1; });
Upvotes: 1