Internally, lambdas are structs with the "function call" operator overload. Context is done via members of the struct: capture by-value, and the struct copies them and stores its own, capture by reference, and the struct member is a reference. There should be zero heap allocation in any case.
If I'm reading this right, then "lambda" in C++ isn't "lambda" in Scheme/CommonLisp, where captured variables need be heap allocated rather than stack allocated to construct closures?
You're right. Lambdas in C++ are syntactic sugar over something the core language has allowed you to do since before C++98. Since you control which variables you capture into the closure, and how, when writing the lambda, all of the information regarding how to make it (e.g. it's size, data members, etc) is static, and so it does not require the use of the heap at all. A concrete example. The following C++ examples do the same thing, and neither touch the heap:
// A. Using a struct. The old manual way.
struct my_lambda {
my_lambda(int c) : c_(c) {}
int operator() (int x) const {
return x == c_;
}
int c_;
};
auto f(vector<int> numbers) {
my_lambda lam(2);
// remove all the matching elements
erase_if(numbers, lam);
return numbers;
}
// B. Using a lambda
auto g(vector<int> numbers) {
int c = 2;
erase_if(numbers, [c](int x) { return x == c; });
return numbers;
}
It is complicated. In C++ closures can close over local variables either by value or by reference (the choice can be made for each variable closed over).
When closing over a variable by reference, if the lambda need to survive the local scope heap allocating the closure itself won't help. Instead you need to explicitly heap allocate the closed over variable itself (and close over the, usually smart, pointer).
When closing over by vale, there is no such issue, closed over variables are copied over along the lambda and it can be safely, for example, be returned from a function.
Copying might be expensive if the lambda is closing over an expensive to copy object, but move semantics are always an option.
Lambdas are value types, they are usually copied around. so when closing over ither va
That's dependent on the captured type's copy (or move) behavior, and is completely different from your claim that how the lambda is used can influence this. Lambdas themselves never heap allocate.
We use Delphi for some of our older applications (everything new is migrating to either C++17 or Go). I remember upgrading the IDE (forget which version, but it was about 3 years ago) and after loading my project, I hit F1 to bring up the help menu. The whole IDE crashed... Between little surprises like that and the insane licensing price, I'm glad we're moving off of it. I don't have any objections to the language itself, but the tooling just isn't where it needs to be.
Lock guard has no default constructor, so the line will in fact materialize a temporary lock guard around the mutex m, then throw it away at the semi-colon, thus locking nothing.
readonly was the original proposed name, if I remember my D&E [0] correctly. Bjarne outlined in that book why he went with const instead, but I forget why off the top of my head. I guess it's tine for a re-read!