c++c++11boostboost-function

Bind a valid class object pointer to boost::function<>fn. What may happen if invoking the `fn` after the object has been destoryed?


Bind a class member function and a valid class object pointer to boost::function<>fn. What may happen if invoking the fn after the object which the pointer pointed to has been destroyed? Are there some potential problems that I should be aware of? Domo code snappet:

 class CTest
 {
    public:
         int demo(void){}
 };

 
 int main()
 {
    boost::function<int(void)> fn;
    {
        CTest ins;
        fn = boost::bind(&CTest::demo, &ins); 
    }
    fn();
}

Edited(https://godbolt.org/z/r8EK1G)

Quoted from the comment of j6t

One way to do that is to pass the object by value, not a pointer to the object. Then a copy of the object would be used during the invocation fn(). I think there is still a problem that the object 'tes' is out of scope.So passing value is not a good method. :

 #include<functional>
 #include<iostream>

 class CTest
 {
    public:
         int demo(void){std::cout << "do better" << std::endl;return 0;}
 };

template <class T=CTest>
std::function<int(void)>  bindWarp(T obj, int (T::*mem_func)(void))
{
    return std::bind(mem_func, obj);
}

 int main()
 {
    std::function<int(void)> fn;
    {
        CTest tes;
        fn = bindWarp(tes, &CTest::demo);  
    }
    fn();  //I think there is still a problem that the object 'tes' is out of scope.So passing value is not a good method.
}

Solution

  • You need to ensure that the target object's lifetime exceeds the function object's lifetime. This is easier to express in an obvious way with a lambda function instead of bind. The lambda can explicitely capture the object 'by-value':

    std::function<int(void)> fn;
    {
        CTest tes;
        fn = [tes] { tes.demo(); };
    }
    fn();
    

    With std::bind you can also explicitely express this, and avoid a copy, by writing:

    fn = std::bind(&CTest::demo, std::move(tes));
    

    You could also pass to bind by-value instead of by-reference but I would prefer the two constructs above because they make the intention very clear (copying the object or transfering ownership).

    If you want to avoid a copy or transfer of ownership, you may use a shared pointer with the lambda instead. You could even go as far as using a weak_ptr within the lambda, so the object is not kept alive for it.

    See also this very helpful discussion about the details of binds & lambdas in modern C++: https://stackoverflow.com/a/17545183/21974