Memory requirements for C++ lambdas - c++

C++ lambdas produce an std::function. In order be able to execute the lambda later, all this state needs to be stored somewhere. So where are these captured values stored and what allocator requirements must be present for this to work?
Also is there any way to vary this behaviour if desired?

A lambda expression does not create a std::function object. Instead, it creates an object (a closure object) of an unnamed class type called the closure type. That closure type will have the following components:
operator()
One member variable for each capture by copy
Potentially member variables for captures by reference
If it has no captures, a conversion operator to a pointer to function
Auto-generate copy constructor
Potentially an auto-generated move constructor
It is guaranteed to have:
No default constructor
No copy/move assignment operator
Nothing else is guaranteed by the standard. The closure type's member variables, like any other member variables, have automatic storage duration; that is, they're contained inside the closure object itself. There are no special allocator requirements, and there is no way to change how these members are managed.

Lambdas are an unnamed type that can be stored in a std::function. Important distinction there. You can think of the declaration of a lambda as very similar to the declaration of a functor class. Example:
std::vector<int> vec(......);
auto& lambda = [vec](int x) -> void {};
We created a copy of vec and receive an int at call time on the stack. Your lambda in this case is roughly equivalent to this class
class mylambda
{
public:
mylambda(const std::vector& vecin) : vec(vecin) {}
void operator() (int x) const {}
private:
std::vector<int> vec;
};
Note that your by-value captures are copied in. Reference captures are stored essentially as pointers. In all likelihood your compiler will defer construction of the lambda for as long as possible. Eventually though, the captures will be stored in the object.
Back to std::function - if you choose to copy the lambda into a function object, because you maybe want to pass it outside the owning function, then your lambda object will be copied (or moved, depending on your syntax) into the function object. In the example above, your function object would indeed store a vector, though keep in mind that the vector stores its payload on the heap (possibly using a custom allocator).

C++ lambdas produce an std::function.
No they don't. They produce an object of class type, with an overloaded operator() so that they can be called like a function.
std::function is a wrapper for any callable type, including lambdas.
In order be able to execute the lambda later, all this state needs to be stored somewhere.
Indeed, captured values need to be stored in the lambda.
So where are these captured values stored and what allocator requirements must be present for this to work?
Captured values are stored as members of the lambda class. References to local variables might be treated similarly; or might be optimised to capture a single pointer to the stack frame containing them.
Also is there any way to vary this behaviour if desired?
No.

Beside the confusion between lambdas and std::function, at least part of your question can be rephrased as:
where does std::function stores its state?".
Either in a small buffer inside std::function itself, or it will allocate a chunk of memory using the default allocator to store the state.
Although it is largely unspecified whether a generic object of type T will fit the first or the second category, std::reference_wrapper is guaranteed to make use of small buffer optimization; that is, the following line:
std::function<void()> f = std::ref( function_object );
does not contain any heap allocation.
Also is there any way to vary this behaviour if desired?
Take a look at the definition of the std::function constructors: most of them take an additional Allocator parameter, that allows you to specify a custom allocator. I assume that the allocator, if stateful, will get copied and type-erased inside the memory provided by the allocator itself.

Related

Why are copy-capturing lambdas not default DefaultConstructible in c++20

C++20 introduces DefaultConstructible lambdas. However, cppreference.com states that this is only for stateless lambdas:
If no captures are specified, the closure type has a defaulted default constructor. Otherwise, it has no default constructor (this includes the case when there is a capture-default, even if it does not actually capture anything).
Why does this not extend to lambdas that capture things that are DefaultConstructible? For instance, why can [p{std::make_unique<int>(0)}](){ return p.get(); } not be DefaultConstructible, where the captured p would be nullptr?
Edit: For those asking why we would want this, the behavior only seems natural because one is forced to write something like this when calling standard algorithms that require functors to be default-constructible:
struct S{
S() = default;
int* operator()() const { return p.get(); }
std::unique_ptr<int> p;
};
So, we can pass in S{std::make_unique<int>(0)}, which does the same thing.
It seems like it would be much better to be able to write [p{std::make_unique<int>(0)}](){ return p.get(); } versus creating a struct that does the same thing.
There are two reasons not to do it: conceptual and safety.
Despite the desires of some C++ programmers, lambdas are not meant to be a short syntax for a struct with an overloaded operator(). That is what C++ lambdas are made of, but that's not what lambdas are.
Conceptually, a C++ lambda is supposed to be a C++ approximation of a lambda function. The capture functionality is not meant to be a way to write members of a struct; it's supposed to mimic the proper lexical scoping capabilities of lambdas. That's why they exist.
Creating such a lambda (initially, not by copy/move of an existing one) outside of the lexical scope that it was defined within is conceptually vacuous. It doesn't make sense to write a thing bound to a lexical scope, then create it outside of the scope it was built for.
That's also why you cannot access those members outside of the lambda. Because, even though they could be public members, they exist to implement proper lexical scoping. They're implementation details.
To construct a "lambda" that "captures variables" without actually capturing anything only makes sense from a meta-programming perspective. That is, it only makes sense when focusing on what lambdas happen to be made of, rather than what they are. A lambda is implemented as a C++ struct with captures as members, and the capture expressions don't even technically have to name local variables, so those members could theoretically be value initialized.
If you are unconvinced by the conceptual argument, let's talk safety. What you want to do is declare that any lambda shall be default constructible if all of its captures are non-reference captures and are of default constructible types. This invites disaster. Why?
Because the writer of many such lambdas didn't ask for that. If a lambda captures a unique_ptr<T> by moving from a variable that points to an object, it is 100% valid (under the current rules) for the code inside that lambda to assume that the captured value points to an object. Default construction, while syntactically valid, is semantically nonsense in this case.
With a proper named type, a user can easily control if it is default constructible or not. And therefore, if it doesn't make sense to default construct a particular type, they can forbid it. With lambdas, there is no such syntax; you have to impose an answer on everyone. And the safest answer for capturing lambdas, the one that is guaranteed to never break code, is "no."
By contrast, default construction of captureless lambdas can never be incorrect. Such functions are "pure" (with respect to the contents of the functor, since the functor has no contents). This also matches with the above conceptual argument: a captureless lambda has no proper lexical scope and therefore spawning it anywhere, even outside of its original scope, is fine.
If you want the behavior of a named struct... just make a named struct. You don't even need to default the default constructor; you'll get one by default (if you declare no other constructors).

std::function internal memory organization and copies; passing reference vs value

When a std::function is copied, are the code instructions it references copied as well?
An std::function is initialized via some form of callable, that points to executable code in some way (like a function pointer typically does). Now, when a function-object is copied, is this executable code runtime copied or internally referenced?
To rephrase the question: If one instance of std::function is copied, are there then multiple copies of the same compiled code instructions in memory?
Is std::function an object that actually stores the function code or is it more an abstraction for a function pointer?
The former would seem wasteful and I don't suspect it, but everything I found so far on the subject is either too vague, lacking or too specific for me to say for me for sure. For example
When the target is a function pointer or a std::reference_wrapper, small object optimization is guaranteed, that is, these targets are always directly stored inside the std::function object, no dynamic allocation takes place. Other large objects may be constructed in dynamic allocated storage and accessed by the std::function object through a pointer. - cppreference
gives some hints about how it's done but seems still too vague and maybe is not related at all to this question, because of further abstractions inside of std::function.
For context: I am trying to refactor some bad C-ish code that maps input-events (keystrokes, mouse input and the like) to a certain behavior, which is executed upon a target data structure which can be interpreted by the program as more specific input that have semantic context other than than keystrokes (, aka keybindings). One can suspect that requirements of behaviours varies drastically.
This was previously implemented with lists of defines and numbers specifying input-event-ids, and hard-coded behavior, which was selected by switch-case. We quickly approach the border of where this intial way of doing it becomes unwieldly.
To get out of the defined lists to an expandable, declarative, object oriented and flexible design I consider higher order functions.
Especially since some behavior is quite simple and repeatedly needed (like for example the toggle of one value in the output data structure) other behaviors are more complex with multiple conditions attached, I'd like to declare some of the behavior statically, but still would like to be open to just assign some special lambda in some cases. Since I need to store behavior per input (key, mousebutton, mouse-axis, etc.) and potentially many copies of one certain behaviour type can be instantiated in one time for different sets of keybindings, I wonder if this behavior should be referenced, rather than stored by value. In the former case, fresh lambdas would need to be owned by the behavior structures, but statically declared behavior does not, which pragmatically would lead to some shared_ptr shenanigans. In the latter case, by value, this would not be an issue, but I wouldn't want multiple copies of for example the toggle behavior to cause too much redundant overhead instead.
(Note: the whole discussion below is a little simplified. AFAIK, none of it is wrong, but I did omit some details and edge cases and definitions and implementation stuff.)
The std::function does not copy any executable code. The executable code is always merely pointed to, by std::function. And when the std::function gets copied, the pointer gets duplicated (which is completely fine, because executable code is never freed either.) So far, there is no difference between a plain old function pointer and a std::function.
But that's not the whole story.
Contrary to function pointers, instances of std::function can carry around "state" as well as a pointer to the executable code, and the whole hubbub about std::function having to allocate/deallocate and copy/move data around is about this extra state, not the function pointer.
Suppose that you have code like this:
(And note that although I've used a lambda here, the following explanation would have been equally applicable for "functors" and "function objects" and "bind results" and other forms of callable things in C++, all except plain old function pointers.)
int x = 42, y = 17;
std::function<int()> f = [x, y] {return x + y;};
Here, f not only stores the pointer to the executable code for return x + y;, but it also has to remember the value of x and y. Since the amount of state that you can "capture" in this way is not limited, then - by definition - the std::function must allocate memory from the heap upon construction, and deallocate it, copy it and move it at appropriate times. Again, it is this extra "state" that gets copied, not the code.
Let's review: each std::function needs to be able to store at least a pointer to executable code, and 0 or more bytes of extra captured state. If there is no captured state, a std::function is essentially the same as a function pointer (although in practice, std::functions are usually implemented polymorphically and have other stuff in there.)
Some (most) implementations of std::function that I'm aware of employ an optimization that is called "Small Object Optimization". In these implementations, in addition to the space for the pointer to code, the std::function object has some more (fixed amount of) space inside its instance (i.e. as a member of its class, as opposed to somewhere else on the heap) and will use that area if the total number of bytes of the captured state would fit in there. This eliminates the heap allocation, which is important in some use cases and would balance out the additional memory used (when there is no or little state to capture.)
I think the information in regarding the exceptions share some light:
Does not throw if other's target is a function pointer or a std::reference_wrapper, otherwise may throw std::bad_alloc or any exception thrown by the constructor used to copy or move the stored callable object. CppReference
This seems to imply that every copy of the std::function copies the contained callable as well. For example, in case your function contains a lambda with a vector, that lambda and by result vector gets copied. The actual machine code that is linked to it, stays in the read-only part of your executable and won't be copied.
An update from the c++20 standard draft: 20.14.16.2.1 Constructors and destructor[func.wrap.func.con]
function(const function& f);
Postconditions: !*this if !f; otherwise, *this targets a copy off.target().
Throws: Nothing iff’s target is a specialization ofreference_wrapperor
a function pointer. Otherwise, may throwbad_allocor any exception
thrown by the copy constructor of the stored callable object.
[Note:
Implementations should avoid the use of dynamically allocated memory
for small callable objects for example, where f’s target is an object holding only a pointer or reference to an object and a member function pointer. — end note]
It seems that std::function does only manage one callable.
If copied, what happens to code is specified by the callable itself.
In a function pointer case, only a function pointer needs to be copied.
In a lambda or custom callable case this would be determined by the implementation of the copy of lambdas or any custom callable class.
These latter 2 typically can hold members of their own, outside of the reference to code. Therefore some space must be allocated by std::function to accomodate these cases. This is however misleading as it could seem std::function as allocating space for code. The management of instruction code seems to be done by the callable however this is done internally there.
In this context default behavior of typically used callables (like lambdas) when copied seems far more interesting for the intended question, but does seem to strech the posed question too far out of the bounds of the context of std::function.
I therefore would consider this question as solved as posed and deepen my knowledge about how lamdas are implemented especially in regards to how they are compiled and the compiled code referenced.

Why std::function<boost::any ()> won't work in this situation?

I faced a situation where I want this kind of function:
MoveOnly createMoveOnly();
Stored here:
std::function<boost::any ()> factory = &createMoveOnly;
This should work, AFAIK, because MoveOnly is convertible to boost::any
Using boost 1.55 which supports move semantics for boost.any, it does not work. It triggers an error about trying to use the deleted copy constructor for MoveOnlyinternally in the holder for boost::any. But the top-level constructor for Boost.Any is correctly chosen (It uses a templated ValueType && that forwards parameters).
Maybe the problem is in std::function.
Any hints?
I think that boost::any requires a copy constructor and assignment operator. The documentation seems to indicate this:
As the emphasis of a value lies in its state not its identity, values can be copied and typically assigned one to another, requiring the explicit or implicit definition of a public copy constructor and public assignment operator. Values typically live within other scopes, i.e. within objects or blocks, rather than on the heap. Values are therefore normally passed around and manipulated directly as variables or through references, but not as pointers that emphasize identity and indirection.
http://www.boost.org/doc/libs/1_55_0/doc/html/any/reference.html

Pass initializer list or container, looking towards move semantics?

EDIT: Before we begin, this question is not about proper usage of std::initializer_list; it is about what should be passed when the convenient syntax is desired. Thank you for staying on topic.
C++11 introduces std::initializer_list to define functions accepting braced-init-list arguments.
struct bar {
bar( char const * );
bar( int );
} dog( 42 );
fn foo( std::initializer_list< bar > args );
foo( { "blah", 3, dog } );
The syntax is nice, but under the hood it is distasteful due to various problems:
They cannot be meaningfully moved. The above function must copy dog from the list; this cannot be converted to move-construction or elided. Move-only types cannot be used at all. (Well, const_cast would actually be a valid workaround. If there's an article about doing so, I'd like to see it.)
There are no constexpr semantics, either. (This is forthcoming in C++1y. It's a minor issue, though.)
const does not propagate as it does everywhere else; the initializer_list is never const but its contents always are. (Because it doesn't own its contents, it cannot give write access to a copy, although copying it anywhere would seldom be safe.)
The initializer_list object does not own its storage (yikes); its relationship to the completely separate naked array (yikes) providing the storage is hazily defined (yikes) as the relationship of a reference to a bound temporary (quadruple yikes).
I have faith these things will be fixed in due time, but for now is there a best practice to get the advantages without hard-coding to initializer_list? Is there any literature about or analysis into working around direct dependency on it?
The obvious solution is to pass by value a standard container such as std::vector. Once the objects are copied into it from the initializer_list, it is move-constructed to pass by value, and then you can move the contents out. An improvement would be to offer storage on the stack. A good library might be able to offer most of the advantages of initializer_list, array, and vector, without even using the former.
Any resources?
it is about what should be passed when the convenient syntax is desired.
If you want the convenience of size (ie: the user just types a {} list with no function calls or words), then you must accept all the powers and limitations of a proper initializer_list. Even if you try to convert it into something else, like some form of array_ref, you still have to have an intermediary initializer_list between them. Which means that you can't get around any of the issues you've run into, like not being able to move out of them.
If it goes through an initializer_list, then you have to accept these limitations. Therefore, the alternative is to not go through an initializer_list, which means that you're going to have to accept some form of container with specific semantics. And the alternative type would have to be an aggregate, so that the construction of the alternate object won't encounter the same problem.
So you're probably looking at forcing the user to create a std::array (or a language array) and passing that. Your function could take some form of array_ref class, which can be constructed from any array of arbitrary size, so the consuming function isn't limited to one size.
However, you lose the convenience of size:
foo( { "blah", 3, dog } );
vs.
foo( std::array<bar, 3>{ "blah", 3, dog } );
The only way to avoid the verbosity here is to have foo take std::array as a parameter. Which means that it could only take an array of a specific fixed size. And you couldn't use C++14's proposed dynarray, because that will use an initializer_list intermediary.
Ultimately, you shouldn't be using uniform initialization syntax for passing around lists of values. It's for initializing objects, not for passing lists of things. std::initializer_list is a class who's sole purpose is to be used to initialize a specific object from an arbitrarily long list of values of identical types. It is there to serve as an intermediary object between a language construct (a braced-init-list) and the constructor that these values are to be fed into. It allows the compiler to know to call a particular constructor (the initializer_list constructor) when given a matching braced-init-list of values.
This is the entire reason why the class exists.
Therefore, you should use the class exclusively for the purpose for which it was devised. The class exists to tag a constructor as taking a list of values from a braced-init-list. So you should use it only for constructors that take such a value.
If you have some function foo that acts as an intermediary between some internal type (that you don't want to directly expose) and a user-provided list of values, then you need to take something else as a parameter to foo. Something that has the semantics you desire, which you can then feed into your internal type.
Also, you seem to have a misconception around initializer_lists and movement. You cannot move out of an initializer_list, but you can certainly move into one:
foo( { "blah", 3, std::move(dog) } );
The third entry in the internal dog array will be move-constructed.

Should I copy an std::function or can I always take a reference to it?

In my C++ application (using Visual Studio 2010), I need to store an std::function, like this:
class MyClass
{
public:
typedef std::function<int(int)> MyFunction;
MyClass (Myfunction &myFunction);
private:
MyFunction m_myFunction; // Should I use this one?
MyFunction &m_myFunction; // Or should I use this one?
};
As you can see, I added the function argument as a reference in the constructor.
But, what is the best way to store the function in my class?
Can I store the function as a reference since std::function is just a function-pointer and the 'executable code' of the function is guaranteed to stay in memory?
Do I have to make a copy in case a lambda is passed and the caller returns?
My gut feeling says that it's safe to store a reference (even a const-reference). I expect the compiler to generate code for the lambda at compile time, and keep this executable code in 'virtual' memory while the application is running. Therefore the executable code is never 'deleted' and I can safely store a reference to it. But is this really true?
Can I store the function as a reference since std::function is just a function-pointer and the 'executable code' of the function is guaranteed to stay in memory?
std::function is very much not just a function pointer. It's a wrapper around an arbitrary callable object, and manages the memory used to store that object. As with any other type, it's safe to store a reference only if you have some other way to guarantee that the referred object is still valid whenever that reference is used.
Unless you have a good reason for storing a reference, and a way to guarantee that it remains valid, store it by value.
Passing by const reference to the constructor is safe, and probably more efficient than passing a value. Passing by non-const reference is a bad idea, since it prevents you from passing a temporary, so the user can't directly pass a lambda, the result of bind, or any other callable object except std::function<int(int)> itself.
If you pass the function in to the constructor by reference, and don't make a copy of it, you'll be out of luck when the function goes out of scope outside of this object, as the reference will no longer be valid. That much has been said in the previous answers already.
What I wanted to add was that, instead, you could pass the function by value, not reference, into the constructor. Why? well, you need a copy of it anyway, so if you pass by value the compiler can optimize away the need to make a copy when a temporary is passed in (such as a lambda expression written in-place).
Of course, however you do things, you potentially make another copy when you assign the passed in function to the variable, so use std::move to eliminate that copy. Example:
class MyClass
{
public:
typedef std::function<int(int)> MyFunction;
MyClass (Myfunction myFunction): m_myfunction(std::move(myFunction))
{}
private:
MyFunction m_myFunction;
};
So, if they pass in an rvalue to the above, the compiler optimises away the first copy into the constructor, and std::move removes the second one :)
If your (only) constructor takes a const reference, you will need to make a copy of it in the function regardless of how it's passed in.
The alternative is to define two constructors, to deal with lvalues and rvalues separately:
class MyClass
{
public:
typedef std::function<int(int)> MyFunction;
//takes lvalue and copy constructs to local var:
MyClass (const Myfunction & myFunction): m_myfunction(myFunction)
{}
//takes rvalue and move constructs local var:
MyClass (MyFunction && myFunction): m_myFunction(std::move(myFunction))
{}
private:
MyFunction m_myFunction;
};
Now, you handly rvalues differently and eliminate the need to copy in that case by explicitly handling it (rather than letting the compiler handle it for you). May be marginally more efficient than the first but is also more code.
The (probably seen a fair bit around here) relevant reference (and a very good read):
http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
I would suggest you to make a copy:
MyFunction m_myFunction; //prefferd and safe!
It is safe because if the original object goes out of scope destructing itself, the copy will still exist in the class instance.
Copy as much as you like. It is copyable. Most algorithms in standard library require that functors are.
However, passing by reference will probably be faster in non-trivial cases, so I'd suggest passing by constant reference and storing by value so you don't have to care about lifecycle management. So:
class MyClass
{
public:
typedef std::function<int(int)> MyFunction;
MyClass (const Myfunction &myFunction);
// ^^^^^ pass by CONSTANT reference.
private:
MyFunction m_myFunction; // Always store by value
};
By passing by constant or rvalue reference you promise the caller that you will not modify the function while you can still call it. This prevents you from modifying the function by mistake and doing it intentionally should usually be avoided, because it's less readable than using return value.
Edit: I originally said "CONSTANT or rvalue" above, but Dave's comment made me look it up and indeed rvalue reference does not accept lvalues.
As a general rule (especially if you're using these for some highly threaded system), pass by value. There is really no way to verify from within a thread that the underlying object is still around with a reference type, so you open yourself up to very nasty race and deadlock bugs.
Another consideration is any hidden state variables in the std::function, for whom modification is very unlikely to be thread-safe. This means that even if the underlying function call is thread-safe, the std::function wrapper's "()" call around it MAY NOT BE. You can recover the desired behavior by always using thread-local copies of the std::function because they'll each have an isolated copy of the state variables.