C++ 创建&;时是否可以使用boost::shared\u ptr;在boost::asio异步模式下接受套接字?
对不起,如果我不能给我的问题加一个更好的标题。 我正在调试我的程序,这时我发现了一些非常有趣的事情。代码非常简单。请关注我的评论:C++ 创建&;时是否可以使用boost::shared\u ptr;在boost::asio异步模式下接受套接字?,c++,boost-asio,shared-ptr,C++,Boost Asio,Shared Ptr,对不起,如果我不能给我的问题加一个更好的标题。 我正在调试我的程序,这时我发现了一些非常有趣的事情。代码非常简单。请关注我的评论: //my session class class Session { public: /// Constructor. Session(boost::asio::io_service &io_service) : socket_(io_service) { } boost::asio::ip::tcp::socket&
//my session class
class Session
{
public:
/// Constructor.
Session(boost::asio::io_service &io_service)
: socket_(io_service)
{
}
boost::asio::ip::tcp::socket& socket()
{
return socket_;
}
void async_read(/*...*/);
void async_write(/*...*/);
//blah blah
private:
std::vector<char> inbound_data_;//<---note this variable, but don't mind it until i tell you
std::string outbound_data_;
boost::asio::ip::tcp::socket socket_;
}
typedef boost::shared_ptr<Session> session_ptr; //just for easy reading
//and this is my connection server class
class ConnectionServer {
public:
void ConnectionServer::CreatSocketAndAccept() {
session_ptr new_sess(new Session(io_service_));//<--I created a scope limited shared_ptr
Print()<< "new_sess.use_count()= " << new_sess.use_count() << std::endl;//prints 1
acceptor_.async_accept(new_sess->socket(),//<-used it for async connection acceptance
boost::bind(&ConnectionServer::handle_accept, this,
boost::asio::placeholders::error, new_sess));
Print()<< "new_sess.use_count()= " << new_sess.use_count() << std::endl;//prints 2
}//<-- Scope is ending. what happens to my new_sess? who keeps a copy of my session?
//and now the strangest thing:
void ConnectionServer::handle_accept(const boost::system::error_code& e, session_ptr sess) {
if (!e) {
Print()<< "sess.use_count()= " << sess.use_count() << std::endl;//prints 4 !!!! while I have never copied the session anywhere else in between
Print() << "Connection Accepted" << std::endl;
handleNewClient(sess);
}
else
{
std::cout << "Connection Refused" << std::endl;
}
CreatSocketAndAccept();
}
有些时候:
Basic Debug [C/C++ Application]
SimMobility_Short [10350] [cores: 0]
Thread [1] 10350 [core: 0] (Suspended : Signal : SIGSEGV:Segmentation fault)
malloc_consolidate() at malloc.c:4,246 0x7ffff5870e20
malloc_consolidate() at malloc.c:4,215 0x7ffff5871b19
_int_free() at malloc.c:4,146 0x7ffff5871b19
__gnu_cxx::new_allocator<char>::deallocate() at new_allocator.h:100 0xa4ab4a
std::_Vector_base<char, std::allocator<char> >::_M_deallocate() at stl_vector.h:175 0xab9508
std::_Vector_base<char, std::allocator<char> >::~_Vector_base() at stl_vector.h:161 0xabf8c7
std::vector<char, std::allocator<char> >::~vector() at stl_vector.h:404 0xabeca4
sim_mob::Session::~Session() at Session.hpp:35 0xabea8d
safe_delete_item<sim_mob::Session>() at LangHelpers.hpp:136 0xabef31
sim_mob::ConnectionHandler::~ConnectionHandler() at ConnectionHandler.cpp:40 0xabd7e6
<...more frames...>
gdb
Basic Debug [C/C++ Application]
SimMobility_Short [10498] [cores: 1]
Thread [1] 10498 [core: 1] (Suspended : Signal : SIGSEGV:Segmentation fault)
_int_free() at malloc.c:4,076 0x7ffff5871674
std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() at 0x7ffff639d540
sim_mob::ConnectionHandler::~ConnectionHandler() at ConnectionHandler.cpp:30 0xabd806
boost::checked_delete<sim_mob::ConnectionHandler>() at checked_delete.hpp:34 0xadd482
boost::detail::sp_counted_impl_p<sim_mob::ConnectionHandler>::dispose() at sp_counted_impl.hpp:78 0xadd6a2
boost::detail::sp_counted_base::release() at sp_counted_base_gcc_x86.hpp:145 0x849d5e
boost::detail::shared_count::~shared_count() at shared_count.hpp:305 0x849dd7
boost::shared_ptr<sim_mob::ConnectionHandler>::~shared_ptr() at shared_ptr.hpp:164 0x84a668
sim_mob::ClientHandler::~ClientHandler() at ClientHandler.cpp:42 0xac726d
sim_mob::ClientHandler::~ClientHandler() at ClientHandler.cpp:45 0xac72da
<...more frames...>
gdb
Basic调试[C/C++应用程序]
simu-Short[10498][cores:1]
线程[1]10498[core:1](挂起:信号:SIGSEGV:分段错误)
_malloc.c处的int_free():4076 0x7ffff5871674
std::basic_string::~basic_string()位于0x7ffff639d540
sim_mob::ConnectionHandler::~ConnectionHandler()位于ConnectionHandler.cpp:30 0xabd806
boost::checked_delete()位于checked_delete.hpp:34 0xadd482
boost::detail::sp_counted_impl_p::dispose()位于sp_counted_impl.hpp:78 0xadd6a2
boost::detail::sp_counted_base::release()位于sp_counted_base_gcc_x86.hpp:145 0x849d5e
boost::detail::shared_count::~shared_count()位于shared_count处。hpp:305 0x849dd7
boost::shared_ptr::~shared_ptr()位于shared_ptr.hpp:164 0x84a668
sim_mob::ClientHandler::~ClientHandler()位于ClientHandler.cpp:42 0xac726d
sim_mob::ClientHandler::~ClientHandler()位于ClientHandler.cpp:45 0xac72da
gdb
这是否意味着我的记忆已经被破坏了?我怎样才能做更多的检查?谢谢你这句话是魔术的寓意:
acceptor_.async_accept(new_sess->socket(),//<-used it for async connection acceptance
boost::bind(&ConnectionServer::handle_accept, this,
boost::asio::placeholders::error, new_sess));
acceptor.async\u accept(new\u sess->socket(),//这一行是魔术的所在:
acceptor_.async_accept(new_sess->socket(),//<-used it for async connection acceptance
boost::bind(&ConnectionServer::handle_accept, this,
boost::asio::placeholders::error, new_sess));
acceptor\uu.async\u accept(新的sess->socket(),//您应该能够使用shared\u ptr
,这样,我就可以以相同的方式使用它,而不会出现问题
在内部,asio会保留一份共享\u ptr
(通过boost::bind)的副本,直到它调用handle\u accept
。这就是允许您首先传递共享\u ptr
的原因。如果您没有将其作为参数之一添加,那么它会在对象在您创建的函数中确定范围后立即清理对象
我怀疑您还有其他未定义的行为,使用原始指针无法发现。您应该能够以这种方式使用shared\u ptr
,我以相同的方式使用它,不会出现问题
在内部,asio会保留一份共享\u ptr
(通过boost::bind)的副本,直到它调用handle\u accept
。这就是允许您首先传递共享\u ptr
的原因。如果您没有将其作为参数之一添加,那么它会在对象在您创建的函数中确定范围后立即清理对象
我怀疑您还有其他未定义的行为,使用原始指针无法发现。To(尝试)回答第二个问题:您似乎在对会话发出双重删除。只有从原始指针创建第二个作用域\u ptr时,才可能执行此操作。这是您不应该执行的操作。您是否将会话的原始指针传递给任何反过来创建其作用域ptr的函数
您可以尝试让会话继承启用来自此的\u共享\u。这将解决此问题,因为任何原始指针都使用相同的作用域\u ptr计数器。但您不应将此视为真正的解决方案。真正的解决方案是消除多个作用域\u ptr实例
编辑:添加了另一种调试可能性
您还可以尝试在会话的析构函数中设置断点,并查看第一次/第二次删除的回溯回答第二个问题:您似乎在对会话发出双重删除。只有从原始指针创建第二个作用域\u ptr时,才可能执行此操作。这是您不应该执行的操作。您是否将会话的原始指针传递给任何反过来创建其作用域ptr的函数
您可以尝试让会话继承启用来自此的\u共享\u。这将解决此问题,因为任何原始指针都使用相同的作用域\u ptr计数器。但您不应将此视为真正的解决方案。真正的解决方案是消除多个作用域\u ptr实例
编辑:添加了另一种调试可能性
您还可以尝试在会话的析构函数中设置断点,并查看第一次/第二次删除的回溯。如本文所述,可以将共享指针与Boost.Asio的async_*函数一起使用
根据调用堆栈和行为,看起来至少有一个资源被删除了两次。是否有可能通过原始指针和共享\u ptr
管理会话
使用boost::shared\u ptr进行管理
void ConnectionServer::CreatSocketAndAccept() {
session_ptr new_sess(new Session(io_service_)); // shared pointer
...
}
使用原始指针进行管理:
sim_mob::Session::~Session()
safe_delete_item<sim_mob::Session>() // raw pointer
sim_mob::ConnectionHandler::~ConnectionHandler()
作为旁注,一个常见的习惯用法是让Session
从继承。它允许Session
在异步调用链的整个过程中保持活动状态,方法是将共享指针作为句柄传递给实例来代替它。例如,它允许Session
在异步调用链中保持活动状态nchronous read操作非常出色,只要this()
中的shared\u的结果被绑定为会话::异步\u read
回调的实例句柄。如本文所述,可以将共享指针与Boost.Asio的异步函数一起使用
根据调用堆栈和行为,看起来至少有一个资源被删除了两次。是否有可能通过原始指针和共享\u ptr
管理会话
使用boost::shared\u ptr进行管理
void ConnectionServer::CreatSocketAndAccept() {
session_ptr new_sess(new Session(io_service_)); // shared pointer
...
}
使用原始指针进行管理:
sim_mob::Session::~Session()
safe_delete_item<sim_mob::Session>() // raw pointer
sim_mob::ConnectionHandler::~ConnectionHandler()
作为旁注,一个常见的习惯用法是让会话
从继承。它允许会话
在其异步调用链的整个过程中保持活动状态,方法是将共享指针作为句柄传递给实例,以代替此。例如,它允许