Reputation: 2313
If i have an instance of std::function
that is bound to a member function of an object instance and that object instance goes out of scope and is otherwise destroyed will my std::function
object now be considered to be a bad pointer that will fail if called?
Example:
int main(int argc,const char* argv){
type* instance = new type();
std::function<foo(bar)> func = std::bind(type::func,instance);
delete instance;
func(0);//is this an invalid call
}
Is there something in the standard that specifies what should happen? My hunch is that it will throw and exception because the object no longer exists
EDIT: Does the standard specify what should happen?
Is it undefined behavior?
EDIT 2:
#include <iostream>
#include <functional>
class foo{
public:
void bar(int i){
std::cout<<i<<std::endl;
}
};
int main(int argc, const char * argv[]) {
foo* bar = new foo();
std::function<void(int)> f = std::bind(&foo::bar, bar,std::placeholders::_1);
delete bar;
f(0);//calling the dead objects function? Shouldn't this throw an exception?
return 0;
}
Running this code i receive an output value of 0;
Upvotes: 6
Views: 2552
Reputation: 302817
What will happen is undefined behavior.
The bind()
call will return some object that contains a copy of instance
, so that when you call func(0)
will effectively call:
(instance->*(&type::func))(0);
Dereferencing an invalid pointer, as you would do there if instance
were delete
d, is undefined behavior. It will not throw an exception (although, it's undefined, so it could, who knows).
Note that you're missing a placeholder in your call:
std::function<foo(bar)> func =
std::bind(type::func, instance, std::placeholders::_1);
// ^^^^^^^ here ^^^^^^^^^
Without that, you can't call func(0)
even with a non-deleted instance.
Updating your example code to better illustrate what's going on:
struct foo{
int f;
~foo() { f = 0; }
void bar(int i) {
std::cout << i+f << std::endl;
}
};
With that added destructor, you can see the difference between copying the pointer (in f
) and copying the object that was pointed to (in g
):
foo* bar = new foo{42};
std::function<void(int)> f = std::bind(&foo::bar, bar, std::placeholders::_1);
std::function<void(int)> g = std::bind(&foo::bar, *bar, std::placeholders::_1);
f(100); // prints 142
g(100); // prints 142
delete bar;
f(100); // prints 100
g(100); // prints 142 still, because it has a copy of
// the object bar pointed to, rather than a copy
// of the pointer
Upvotes: 7