Search code examples
c++inheritanceboostshared-ptrboost-bind

boost::bind, boost::shared_ptr and inheritance


I'm new with the Boost library, and I got a problam a bit complex for me. I tried to reformulate it with an example found in previous question that might fit well my problem. (The previous question is here)

#include <boost/bind.hpp>
#include <iostream>
#include <map>
#include <set>
#include <algorithm>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

class Base
    : public boost::enable_shared_from_this<Base>,
      private boost::noncopyable
{
public:
        virtual void test() = 0;

protected:
        virtual void foo(int i) = 0;
};

class Derived
    : public Base
{
protected:
    void foo(int i)
    { std::cout << "Base: " << i << std::endl; }

    std::map<int, int> data;

public:     

    Derived()
    {
            data[0] = 5;
            data[1] = 6;
            data[2] = 7;
    }        

    void test()
    {
        std::for_each(data.begin(), data.end(),
            boost::bind(&Derived::foo, shared_from_this(),
                boost::bind(&std::map<int, int>::value_type::second, _1)));
    }
};

typedef boost::shared_ptr<Base> Base_ptr;

int main(int, const char**)
{

    std::set<Base_ptr> Bases_;
    Base_ptr derived(new Derived());

    Bases_.insert(derived);
    derived->test();


    return 0;
}

I have a base object which is contained in a set, and different derived objects (in this example, only one). The derived object should call his own protected method with a boost::bind. In the real problem, the boost::bind generate a callback method for an asynchronous operation, it's why (I think) I need a shared_ptr. Otherwise, using the pointer this instead of shared_from_this() resolve the problem.

When I compile this code, I got a long error message ended with (which I think is the most significant part):

bind_test.cpp:43:78:   instantiated from here
/usr/include/boost/bind/mem_fn_template.hpp:156:53: error: pointer to member type ‘void (Derived::)(int)’ incompatible with object type ‘Base’
/usr/include/boost/bind/mem_fn_template.hpp:156:53: error: return-statement with a value, in function returning 'void'

I tried to manage with more inheritance from enable_shared_from_this, and some static cast :

#include <boost/bind.hpp>
#include <iostream>
#include <map>
#include <set>
#include <algorithm>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

class Base
    : public boost::enable_shared_from_this<Base>,
      private boost::noncopyable
{
public:
        virtual void test() = 0;

protected:
        virtual void foo(int i) = 0;
};

class Derived
    : public boost::enable_shared_from_this<Derived>,
      public Base
{
protected:
    void foo(int i)
    { std::cout << "Base: " << i << std::endl; }

    std::map<int, int> data;

public:     

    Derived()
    {
            data[0] = 5;
            data[1] = 6;
            data[2] = 7;
    }        

    void test()
    {
        std::for_each(data.begin(), data.end(),
            boost::bind(&Derived::foo, boost::enable_shared_from_this<Derived>::shared_from_this(),
                boost::bind(&std::map<int, int>::value_type::second, _1)));
    }
};

typedef boost::shared_ptr<Base> Base_ptr;

int main(int, const char**)
{

    std::set<Base_ptr> Bases_;
    Base_ptr derived(new Derived());

    Bases_.insert(derived);
    derived->test();


    return 0;
}

But I got an error at run-time :

terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::bad_weak_ptr> >'
  what():  tr1::bad_weak_ptr

Might someone have a clue about how to manage that ? Thanks.

Etienne.


Solution

  • It works with this workaround, but I'm not satisfied with it, so if someone find a better solution, go ahead.

    #include <boost/bind.hpp>
    #include <iostream>
    #include <map>
    #include <set>
    #include <algorithm>
    #include <boost/noncopyable.hpp>
    #include <boost/shared_ptr.hpp>
    #include <boost/enable_shared_from_this.hpp>
    
    class Base
        : public boost::enable_shared_from_this<Base>,
          private boost::noncopyable
    {
    public:
            virtual void test() = 0;
    
    //protected:
            virtual void foo(int i) = 0;
    };
    
    class Derived
        : public Base
    {
    protected:
        void foo(int i)
        { std::cout << "Base: " << i << std::endl; }
    
        std::map<int, int> data;
    
    public:     
    
        Derived()
        {
                data[0] = 5;
                data[1] = 6;
                data[2] = 7;
        }        
    
        void test()
        {
            std::for_each(data.begin(), data.end(),
                boost::bind(&Base::foo, shared_from_this(),
                    boost::bind(&std::map<int, int>::value_type::second, _1)));
        }
    };
    
    typedef boost::shared_ptr<Base> Base_ptr;
    
    int main(int, const char**)
    {
    
        std::set<Base_ptr> Bases_;
        Base_ptr derived(new Derived());
    
        Bases_.insert(derived);
        derived->test();
    
    
        return 0;
    }