boost :: bind, boost :: shared_ptr и наследование

Я новичок в библиотеке Boost, и у меня возникла немного сложная проблема. Я попытался переформулировать это с помощью примера из предыдущего вопроса, который может хорошо соответствовать моей проблеме. (Предыдущий вопрос находится здесь)

#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;
}

У меня есть базовый объект, который содержится в наборе, и разные производные объекты (в этом примере только один). Производный объект должен вызывать свой собственный защищенный метод с помощью boost :: bind. В реальной проблеме boost :: bind генерирует метод обратного вызова для асинхронной операции, поэтому (я думаю) мне нужен shared_ptr. В противном случае использование указателя this вместо shared_from_this () решит проблему.

Когда я скомпилировал этот код, у меня появилось длинное сообщение об ошибке (которое, как мне кажется, является наиболее важной частью):

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'

Я попытался обойтись большим количеством наследований от enable_shared_from_this и некоторым статическим приведением:

#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;
}

Но во время выполнения у меня возникла ошибка:

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

Может кто-нибудь знает, как с этим справиться? Спасибо.

Этьен.


person etnbrd    schedule 07.09.2011    source источник
comment
Выражение bind не имеет смысла по нескольким причинам. Что самое поразительное, так легко добраться до второго члена пары. Можете ли вы переписать сигнатуру функции foo()?   -  person Kerrek SB    schedule 08.09.2011
comment
Наследование от enable_shared_from_this в базе и производном может привести к проблемам. Я бы избегал этого маршрута. stackoverflow.com/questions/657155/   -  person Tom Kerr    schedule 08.09.2011
comment
@Kerrek SB, на самом деле, этот пример действительно проще, чем настоящая проблема. На самом деле я использую boost :: bind для создания функции обратного вызова для асинхронной операции на сокете с именем socket_: void производное :: test () {socket_.async_read_some (boost :: asio :: buffer (buffer_), boost :: bind (& Derived :: foo, shared_from_this (), boost :: asio :: placeholder :: error, boost :: asio :: placeholder :: bytes_transferred)); } foo - это мой обратный вызов, который на самом деле называется handle_read или handle_write.   -  person etnbrd    schedule 08.09.2011
comment
@Tom K, я столкнулся с проблемами из-за этого двойного наследования. Вот почему мне нужно указать: boost :: enable_shared_from_this ‹Derived› :: shared_from_this () вместо: shared_from_this ()   -  person etnbrd    schedule 08.09.2011
comment
@Etienne: Как бы то ни было, это все равно не избавляет вас от необходимости иметь дело со значением карты, равным pair<int,int>. Вы либо пишете небольшую функцию проектора, либо заставляете получателя принять пару ...   -  person Kerrek SB    schedule 08.09.2011
comment
@Kerek SB, в моем реальном коде нет карты. Карта взята из примера, который я использовал для иллюстрации моей проблемы. Если вы хотите увидеть реальную и сложную проблему, взгляните здесь   -  person etnbrd    schedule 08.09.2011


Ответы (1)


Это работает с этим обходным путем, но меня это не устраивает, поэтому, если кто-то найдет лучшее решение, продолжайте.

#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;
}
person etnbrd    schedule 09.09.2011