boost :: shared_ptr, std :: map и valgrind - у меня есть утечка памяти? - PullRequest
1 голос
/ 02 февраля 2011

Хорошо. Я использую boost :: shared_ptr для хранения пары объектов на карте. Целочисленные значения отображаются в shared_ptrs для объектов, которые я использую.

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

Этот код взрывается в valgrind, смотрите сообщение об ошибке ниже. Если вы посмотрите на начало цепочки методов, то увидите, что в классе UdpServer я пересылаю запрос 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)));

Мне нужно выполнить приведение, потому что у меня есть обработчики клиентских сообщений и сетевые / системные обработчики сообщений, которые обрабатывают некоторые другие случаи, такие как ошибки. HandlerMsgHandler вызывается, когда действительное сообщение было отправлено клиенту NetworkHandler.

Я не уверен, сколько вам нужно знать о дизайне, возможно, ошибка для вас очевидна?

UPDATE:

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 ]

2 голосов
/ 02 февраля 2011

Чаще всего, когда я видел утечку памяти, которая указывает на память, выделенную внутри контейнера, это либо то, что правило из трех не соблюдалось, и память просочилась изэлемент, или что весь контейнер просочился.

В вашем конкретном случае это больше похоже на утечку из самого контейнера.Примерно так:

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 голосов
/ 02 февраля 2011

std::map - это красно-черное дерево, и Вэлгринд жалуется на выделение 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 экземпляр.

EDIT, 2 февраля: Ваш деструктор NetworkHandler виртуальный?В противном случае деструктор map<uint8_t boost::shared_ptr<NetworkHandler> > handlers не будет вызван, и у вас будет утечка узла карты.

Ознакомьтесь с C ++ FAQ .

Q: Когда мой деструктор должен быть виртуальным?

A: Когда кто-то удалит объект производного класса через указатель базового класса.Когда вы говорите delete p, а класс p имеет виртуальный деструктор, вызываемый деструктор - это тот, который связан с типом объекта * p, а не обязательно тот, который связан с типом указателя.Это хорошая вещь.

0 голосов
/ 02 февраля 2011

Как сказал vz0, это узел сети, а не обработчик.

Это единственная ошибка, о которой сообщает valgrind? Valgrind сообщает о некоторой прямой утечке, поэтому вы, вероятно, удаляете / очищаете карту по завершении программы, но уверены ли вы, что ваша программа не обращается за пределы какого-либо массива или записывает неинициализированные данные (особое внимание здесь уделяется указателям)? 1003 *

У меня раньше была похожая проблема, это произошло из-за переполнения буфера, связанного с картой.

Примечание: Динамическое приведение проверяет во время выполнения, может ли значение быть приведено к этому типу, если оно не может, оно возвращает NULL. Если вы не будете проверять, имеет ли значение dynamic_cast возвращаемое значение NULL, используйте static_cast, который работает быстрее.

...