Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::function to member function of object and lifetime of object

Tags:

c++

c++11

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;

like image 785
Alex Zywicki Avatar asked Jan 20 '15 20:01

Alex Zywicki


1 Answers

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 deleted, 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
like image 65
Barry Avatar answered Oct 06 '22 15:10

Barry