项目中使用boost::asio,其中的异步调用往往会有一个handler参数,这个参数一般使用动态内存申请的对象和其成员函数构建。
因此如果在asio线程和对象管理线程中间没有适当的同步机制,则很容易造成内存访问错误,如pure virtual method called等。这时候可以使用boost::shared_ptr和enable_shared_from_this(从类实例内获取管理自身的shared_ptr拷贝,引用计数会加1,这个拷贝如果不失效则类实例不能析构)来解决动态内存管理问题:
下面是一个验证enable_shared_from_this的例子
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
class Good;
class Good: public boost::enable_shared_from_this<Good>{
private:
virtual int callback() = 0;
public:
void init_cb()
{
cb = boost::bind(&Good::callback,shared_from_this());
}
void run()
{
cb();
}
boost::shared_ptr<Good> get_shared_ptr()
{
return shared_from_this();
}
virtual ~Good()
{
std::cout<<"~Good"<<std::endl;
}
private:
boost::function<int()> cb;
};
class SonOfGood:public Good{
virtual int callback(){
std::cout<<"Callback"<<std::endl;
}
public:
virtual ~SonOfGood()
{
std::cout<<"~SonOfGood"<<std::endl;
}
};
void func(boost::shared_ptr<Good> & gp1)
{
std::cout << "gp1.use_count() = " << gp1.use_count() << '\n';
boost::shared_ptr<Good> cb = gp1->get_shared_ptr();
std::cout << "gp1.use_count() = " << gp1.use_count() << '\n'; // 计数应该加1
}
int main(){
boost::shared_ptr<Good> gp1(new SonOfGood);
std::cout << "gp1.use_count() = " << gp1.use_count() << '\n'; // 应该为1
func(gp1);
std::cout << "gp1.use_count() = " << gp1.use_count() << '\n'; // 应该为1
std::cout << "gp1.use_count() = " << gp1.use_count() << '\n'; // 应该为1
gp1->init_cb(); // 从gp1创建了boost::function<int()>,使用了shared_from_this(),use_count会加1
std::cout << "gp1.use_count() = " << gp1.use_count() << '\n'; // 应该为2
gp1->run();
std::cout << "gp1.use_count() = " << gp1.use_count() << '\n'; // 应该为2
}
具体使用还可以参考 mongodb代码,其中的message_server_asio.cpp文件中有非常好的例子。