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

发布于 2024-10-15 17:32:05 字数 7077 浏览 5 评论 0 原文

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

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 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)

Alright. I am using boost::shared_ptr to store a couple of objects in a map. Integer values maps to shared_ptrs to objects that I am using.

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

This code blows up in valgrind, look below for the error message. If you look at the beginning of the method chain, you can see that in the UdpServer class I forward the addHandler request from my testclass into an inner class called HandlerMsgHandler.

This is how that method looks like:

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

And the callsite:

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

I need to cast because I have client message handlers, and network/system message handlers which handle certain other cases such as errors. The HandlerMsgHandler is invoked when a valid message has been sent to a client NetworkHandler.

I'm not sure how much you need to know about the design, perhaps the mistake is obvious to you?

UPDATE:

sysMsgHandlers is declared as std::map<SysMessage, NetworkHandler*> sysMsgHandlers;, while the sysMsgHandlers are initiated internally as such:

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

I don't use any fancy pointer types here since it's all internal. I iterate over the sysMsgHandlers map and delete the pointers (I have verified that this happens).

UPDATE 2:

More info. I am deleting the object containing the map.

I have this code in my UdpServer destructor:

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

This gives the following output to std::cout: (among a few other debug messages)

 : 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

And this is still the valgrind output:

==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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

彼岸花ソ最美的依靠 2024-10-22 17:32:05

std::map 是红黑树,valgrind 抱怨 std::_Rb_tree_node 的分配。 >。地图树的节点是泄漏的节点。

我猜这个转换一定与泄漏有关:

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

你确定表达式sysMsgHandlers[network::handler]返回一个指针(而不是 >boost::shared_ptr) 到 HandlerMsgHandler?

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

编辑,2 月 2 日: 您的 NetworkHandler 析构函数是虚拟的吗?如果不是,则调用map的析构函数。 > handlers 不会被调用,并且您会在那里泄漏地图的节点。

查看C++ 常见问题解答

问:我的析构函数什么时候应该是虚拟的?

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

An std::map is a Red-Black Tree, and valgrind complains about the allocation of an std::_Rb_tree_node<std::pair<..., ...> >. The node of the map's tree is the one leaking.

I guess this cast must be related to the leak:

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

Are you sure that the expression sysMsgHandlers[network::handler] returns a pointer (and not a boost::shared_ptr) to HandlerMsgHandler?

EDIT: The next most probable cause is that sysMsgHandlers[handler] returns an ErrorMsgHandler instance.

EDIT, 2 Feb: Is your NetworkHandler destructor virtual? If not, the destructor of map<uint8_t boost::shared_ptr<NetworkHandler> > handlers won't get called and you'd have a leak of the map's node there.

Check out the C++ FAQ.

Q: When should my destructor be virtual?

A: When someone will delete a derived-class object via a base-class pointer.
When you say delete p, and the class of p has a virtual destructor, the destructor that gets invoked is the one associated with the type of the object *p, not necessarily the one associated with the type of the pointer. This is A Good Thing.

咋地 2024-10-22 17:32:05

通常,当我看到内存泄漏指向容器内分配的内存时,要么是 没有遵循三者法则,内存被包含的元素泄漏,或者整个容器被泄漏。

在您的特定情况下,它看起来更像是容器本身正在泄漏。类似于:

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>

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

More often than not, when I've seen a memory leak that points to memory allocated inside a container it is either that the rule of the three is not been followed and memory is leaked by the contained element, or else that the whole container is leaked.

In your particular case, it looks more like the container it self is being leaked. Something like:

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>

Note that the code marked with [*] need not be so obvious. The map can be a member of a class that is being dynamically allocated and never deleted.

泛滥成性 2024-10-22 17:32:05

就像 vz0 所说,泄漏的是地图的节点,而不是处理程序。

这是 valgrind 报告的唯一错误吗? Valgrind 报告了一些直接泄漏,因此您可能在程序完成时删除/清除映射,但是您确定您的程序没有访问任何数组的边界之外或写入未初始化的数据(此处特别注意指针)?

我以前也遇到过类似的问题,碰巧是缓冲区溢出导致地图混乱。

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

Like vz0 said, it is the map's node that is leaking, not the handler.

Is this the only error valgrind is reporting? Valgrind report some direct leaking, so you are probably deleting/clearing the map when the program finish, but are you sure your program is not accessing out side the bound of any array or writing on uninitialized data (special care with pointers here)?

I have had a similar problem before, it happened to be a buffer overflow which was messing with the map.

Note: Dynamic cast checks at runtime if the value can be cast to that type, if it cannot, it return NULL. If you will not check if the return of dynamic_cast is NULL, then use static_cast, which is faster.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文