The following code compiles but yields undefined output in VC++ 2015 (release) and a runtime error with other compilers.
#include <functional>
#include <iostream>
int main()
{
std::function<int(int)> f = [](int x) { return x; };
std::function<const int&(const int& x)> g = f;
std::cout << g( 42 ) << std::endl;
}
Why is the assignment g = f;
allowed?
On g++, a non-trivial copy constructor on a function object, or data exceeding 16 bytes, is enough to cause it to allocate. But if your function object has no data and uses the builtin copy constructor, then std::function won't allocate.
Instances of std::function can store, copy, and invoke any CopyConstructible Callable target -- functions (via pointers thereto), lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.
std::function is a type erasure object. That means it erases the details of how some operations happen, and provides a uniform run time interface to them. For std::function , the primary1 operations are copy/move, destruction, and 'invocation' with operator() -- the 'function like call operator'.
It lets you store function pointers, lambdas, or classes with operator() . It will do conversion of compatible types (so std::function<double(double)> will take int(int) callable things) but that is secondary to its primary purpose.
Consider the equivalent code rewritten to avoid lambdas or std::function
:
int f(int x) { return x; }
int const& g(int const& x) { return f(x); }
This is perfectly well-formed code, that nevertheless returns a dangling reference to a temporary and thus will end up causing undefined behavior. The original code is vaid for the same reason: you can implicitly convert an object to a reference of the same type. Unfortunate, in this case.
An rvalue can be bound to a const&
. A const&
can be converted to an rvalue.
Examine this:
int f(int x){return x;}
int const& g(int const& x){ return f(x); }
Similarly, the call to g
is legal, there are no errors, yet reading the result of g(42)
is UB -- the reference dangles.
A good compiler will see the reference bound to temporary being returned and warn.
function
simply checks if the types can be converted between; it does no lifetime analysis. Possibly it should, as we can detect this error statically.
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