项目中使用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文件中有非常好的例子。