When I convert a lambda to an std::function object, it gets converted and in case less than 24 bytes are captured (e.g. this pointer), std::function doesn't issue a heap alloc.
Now my question is how can I construct my own functor from a lambda and extract this-ptr from the lambda to save it in my functors memory layout?
Related
I have a lambda I'm storing into an std::function to be called in a separate thread, that looks like this:
void * specialMalloc(size_t size); // provides annointed memory; beloved by all
int n;
std::function f = [=]()mutable -> void {
printf("%i", n);
};
Is it possible to create a std::function f that takes this lambda and it's int n, and asks specialMalloc() to carefully prepare memory to place it into? Specifically in C++17, where I've read custom allocators have been deprecated?
There's no way custom to pass allocator in the current C++. std::function will use global operator new. It will not even use class's operator new, instead calling the global one.
However std::function typically employs small object optimization. At least you expect it to engage for pointer-sized functors. Real implementations have buffer for small object optimization for 2-3 pointers, MSVC has much more. With small object optimization, std::function does not use indirect memory at all.
Your functor has a size of int, which is very likely to fit small object optimization. You functor will not cause any allocation function to be called when it is put into std::function.
For larger functors, you can make their data indirect, and allocate it on your own, so that they'll make use of small object optimization, and thus will not use the global operator new
There are other criteria for small object optimization to engage, specifically noexcept copy constructor, and not being overly alignend.
Unfortunately, there's no standard way to query in compile-time whether small object optimization apply, and it is not required by the standard (although recommended for some types of functors)
I think there's not a good way to do this.
Well, std::function had a constructor that took a custom allocator but this functionality was removed in C++17.
Why does a std::thread object accept the function parameter by forwarding reference and then make a copy of the object with decay_copy? Wouldn't it be easier to just accept the function object by value?
In general why would one not template a function so as to take a function object by value? Can reference-ness not be imitated with reference_wrappers (which would be more explicit, and also conveniently has a member operator() to call the stored function)?
Why does a std::thread object accept the function parameter by forwarding reference and then make a copy of the object with decay_copy? Wouldn't it be easier to just accept the function object by value?
It has to have a copy of the function object in a storage that it can guarantee lasts as long as the thread it is about to launch lasts.
A function argument to construct std::thread would not last that long, as the line where std::thread is created can end long before the created thread ends.
So it must make a copy. If it took its argument by-value, it would make a copy when the constructor was called, then have to make another copy to the persistent storage. By taking it by forwarding reference, it makes exactly one copy.
Now this additional copy could be moved-to, making the extra overhead one extra move. This is still extra overhead, as not all constructs are cheap to move.
In general why would one not template a function so as to take a function object by value?
Because that mandates an extra move.
Can reference-ness not be imitated with reference_wrappers (which would be more explicit, and also conveniently has a member operator() to call the stored function)?
In the case where you intend to store the function object, taking by forwarding reference saves a move, and doesn't require much extra work on the part of the writer of the function-object taking code.
If the caller passed in a reference wrapper, the value stored would be the reference wrapper, which has a different meaning.
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.
I have a class which interpolates a 2D function automatically (quite happy with it). It accepts a dynamic function pointer to the method being interpolated. I have had to template out the class, since I need the object instance as well as the pointer.
Can I avoid templating the class out? Or will I need to keep doing so in order to accept the object instance as a parameter? Is a base class possible? (I'm fairly new to c++)
The way I have it is (abbreviated):
template<class F>
class Interpolate {
Interpolate(double (F::*f)(double, double), F & obj, ...) {
...
double value = (object.*f)(x,y);
...
}
}
As pointed out in the comment, you can also use std::function. This give you more flexibility with std::bind. On the other hand, std::function may allocate the resulting function on the heap and this causes a big overhead (which may be avoid by using std::cref() ). A very interesting discussion about the differences in execution time of std::function vs templates can be found at std::function vs template.
" Notice that std::function is able to store different types of callable objects. Hence, it must perform some type-erasure magic for the storage. Generally, this implies a dynamic memory allocation (by default through a call to new). It's well known that this is a quite costly operation. " by Cassio Neri - Here is where std::cref can help, specially because in the example discussed in the link I just wrote, without std::cref, the heap allocation of std::function slowed down the program by a factor 10!
I have a collection (currently boost::ptr_vector) of objects (lets call this vec) that needs to be passed to a few functors. I want all of the functors to have a reference/pointer to the same vec which is essentially a cache so that each functor has the same data cache. There are three ways that I can think of doing this:
Passing a boost::ptr_vector<object>& to the constructor of Functor and having a boost::ptr_vector<object>& member in the Functor class
Passing a boost::ptr_vector<object>* to the constructor of Functor and having a boost::ptr_vector<object>* member in the Functor class
avoid the use of boost::ptr_vector and directly pass an array (object*) to the constructor
I have tried to use method 3, but have been told constantly that I should use a vector instead of a raw pointer. So, I tried method 2 but this added latency to my program due to the extra level of indirection added by the pointer. I am using method 1 at the moment, however I may need to reassign the cache during the lifetime of the functor (as the data cache may change) so this may not be an appropriate alternative.
Which I don't fully understand. I assume somewhere along the way the functor is being copied (although these are all stored in a ptr_vector themselves).
Is method 3 the best for my case? method 2, is too slow (latency is very crucial), and as for method 1, I have been advised time and again to use vectors instead.
Any advice is much appreciated
A reference in C++ can only be initialized ('bound') to a variable.
After that point, a reference can not be "reseated" (made to refer to a different variable) during it's lifetime.
This is why a default copy constructor could conceivably be generated, but never the assignment operator, since that would require the reference to be 'changed'.
My recommended approach here is to use a smart pointer instead of a reference.
std::unique_ptr (simplest, takes care of allocation/deallocation)
std::shared_ptr (more involved, allows sharing of the ownership)
In this case:
std::shared_ptr<boost::ptr_vector<object> > m_coll;
would seem to be a good fit