boost :: shared_ptr,std :: map和valgrind - 我有内存泄漏吗?

时间:2011-02-01 21:57:16

标签: c++ memory-leaks map valgrind shared-ptr

好的。我正在使用boost :: shared_ptr在地图中存储几个对象。整数值映射到shared_ptrs到我正在使用的对象。

void HandlerMsgHandler::addHandler(uint8_t key, boost::shared_ptr<NetworkHandler> handler) 
{
    handlers[key] = handler; 
}

此代码在valgrind中爆炸,请查看下面的错误消息。如果查看方法链的开头,可以看到在UdpServer类中,我将来自testclass的addHandler请求转发到一个名为HandlerMsgHandler的内部类中。

这就是该方法的样子:

void UdpServer::addHandler(uint8_t key, boost::shared_ptr<NetworkHandler> handler)
{
    dynamic_cast<HandlerMsgHandler*>(sysMsgHandlers[network::handler])->addHandler(key, handler);
}

呼叫网站:

server.addHandler(1, boost::shared_ptr<net::NetworkHandler>(new _NetworkHandler(networkHandlerFailed)));
server.addHandler(2, boost::shared_ptr<net::NetworkHandler>(new SimpleIntMessageHandler(simpleIntFailed)));

我需要进行强制转换,因为我有客户端消息处理程序,以及处理某些其他情况(如错误)的网络/系统消息处理程序。当有效消息发送到客户端NetworkHandler时,将调用HandlerMsgHandler。

我不确定您需要了解多少设计,也许这个错误很明显?

更新

sysMsgHandlers声明为std::map<SysMessage, NetworkHandler*> sysMsgHandlers;,而sysMsgHandlers则在内部启动:

sysMsgHandlers[handler] = new HandlerMsgHandler();
sysMsgHandlers[error] = new ErrorMsgHandler();

我不在这里使用任何花哨的指针类型,因为它都是内部的。我遍历sysMsgHandlers地图并删除指针(我已经确认会发生这种情况)。

更新2:

更多信息。我删除包含地图的对象。

我在UdpServer析构函数中有这段代码:

for(auto iter = sysMsgHandlers.begin(); iter != sysMsgHandlers.end(); iter++)
{
LOG("MsgHandlers deleted");
delete iter->second;
}

这给std :: cout提供了以下输出:(在一些其他调试消息中)

 : Listening started
 : Connecting to socket : 1
 : Sending message
 : Received in buffer
 : Received : 24 bytes.
 : Sys msg = 1
 : Handling request to: 1
 : Stopping manager
 : MsgHandlers deleted
 : MsgHandlers deleted

这仍然是valgrind的输出:

==26633== 192 (56 direct, 136 indirect) bytes in 1 blocks are definitely lost in loss record 21 of 35
==26633==    at 0x4C28973: operator new(unsigned long) (vg_replace_malloc.c:261)
==26633==    by 0x4258AF: __gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > > >::allocate(unsigned long, void const*) (new_allocator.h:89)
==26633==    by 0x4257A7: std::_Rb_tree<unsigned char, std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> >, std::_Select1st<std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > >, std::less<unsigned char>, std::allocator<std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > > >::_M_get_node() (stl_tree.h:359)
==26633==    by 0x425622: std::_Rb_tree_node<std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > >* std::_Rb_tree<unsigned char, std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> >, std::_Select1st<std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > >, std::less<unsigned char>, std::allocator<std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > > >::_M_create_node<std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > const&>(std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > const&&&) (stl_tree.h:391)
==26633==    by 0x42526E: std::_Rb_tree<unsigned char, std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> >, std::_Select1st<std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > >, std::less<unsigned char>, std::allocator<std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > > >::_M_insert_(std::_Rb_tree_node_base const*, std::_Rb_tree_node_base const*, std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > const&) (stl_tree.h:881)
==26633==    by 0x4253ED: std::_Rb_tree<unsigned char, std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> >, std::_Select1st<std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > >, std::less<unsigned char>, std::allocator<std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > > >::_M_insert_unique(std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > const&) (stl_tree.h:1177)
==26633==    by 0x424CA9: std::_Rb_tree<unsigned char, std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> >, std::_Select1st<std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > >, std::less<unsigned char>, std::allocator<std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > > >::_M_insert_unique_(std::_Rb_tree_const_iterator<std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > >, std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > const&) (stl_tree.h:1217)
==26633==    by 0x424931: std::map<unsigned char, boost::shared_ptr<chat::server::network::NetworkHandler>, std::less<unsigned char>, std::allocator<std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > > >::insert(std::_Rb_tree_iterator<std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > >, std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > const&) (stl_map.h:540)
==26633==    by 0x42463E: std::map<unsigned char, boost::shared_ptr<chat::server::network::NetworkHandler>, std::less<unsigned char>, std::allocator<std::pair<unsigned char const, boost::shared_ptr<chat::server::network::NetworkHandler> > > >::operator[](unsigned char const&) (stl_map.h:450)
==26633==    by 0x424163: chat::server::network::HandlerMsgHandler::addHandler(unsigned char, boost::shared_ptr<chat::server::network::NetworkHandler>) (sysnetworkhandler.cpp:19)
==26633==    by 0x4120F1: chat::server::network::UdpServer::addHandler(unsigned char, boost::shared_ptr<chat::server::network::NetworkHandler>) (udpserver.cpp:38)
==26633==    by 0x404938: chat::test::server::testCanSendToSelf(bool&) (main.cpp:95)

3 个答案:

答案 0 :(得分:2)

std::map是红黑树,valgrind抱怨std::_Rb_tree_node<std::pair<..., ...> >的分配。地图树的节点就是漏洞。

我猜这个演员必须与泄密有关:

dynamic_cast<HandlerMsgHandler*>(sysMsgHandlers[network::handler])->addHandler(key, handler);

您确定表达式sysMsgHandlers[network::handler]会将指针(而不是boost::shared_ptr)返回到HandlerMsgHandler吗?

编辑:下一个最可能的原因是sysMsgHandlers[handler]返回ErrorMsgHandler个实例。

编辑,2月2日:您的NetworkHandler析构函数是虚拟的吗?如果没有,map<uint8_t boost::shared_ptr<NetworkHandler> > handlers的析构函数将不会被调用,你的地图节点就会泄漏。

查看C++ FAQ

  问:我的析构函数何时应该是虚拟的?

     

答:当有人通过基类指针删除派生类对象时。   当你说删除p,并且p的类有一个虚析构函数时,被调用的析构函数是与对象* p的类型相关联的析构函数,不一定是与指针类型相关联的析构函数。这是一件好事。

答案 1 :(得分:2)

通常情况下,当我看到内存泄漏指向容器内部分配的内存时,要么没有遵循rule of the three而内存被所包含的元素泄露,要么就是整个集装箱都泄漏了。

在您的特定情况下,它看起来更像是自己泄漏的容器。类似的东西:

int main() {
   std::map<int,std::string> *p = new std::map<int,std::string>(); // [*]
   p->insert( std::make_pair( 1, "one" ) );
}
// leaked memory allocated internally in std::map<int,std::string>

请注意,标有[*]的代码不一定非常明显。映射可以是动态分配且永不删除的类的成员。

答案 2 :(得分:0)

就像vz0所说的那样,它是地图的漏洞,而不是处理程序。

这是valgrind报告的唯一错误吗? Valgrind报告了一些直接泄漏,所以你可能在程序结束时删除/清除了地图,但是你确定你的程序没有访问任何数组的边界或写入未初始化的数据(这里特别注意指针)? / p>

之前我遇到过类似的问题,碰巧是一个缓冲区溢出,搞乱了地图。

注意:如果可以将值强制转换为该类型,则在运行时进行动态强制转换检查,如果不能,则返回NULL。如果你不检查dynamic_cast的返回是否为NULL,那么使用static_cast,这会更快。