使用typeinfo :: name()后内存泄漏

ica*_*bod 8 c++ memory-leaks typeid typeinfo visual-c++

我有一个程序,其中,部分用于信息日志记录,我输出一些类的名称,因为它们被使用(特别是我在日志中添加一个条目说明Messages::CSomeClass transmitted to 127.0.0.1).我使用类似于以下代码执行此操作:

std::string getMessageName(void) const {
    return std::string(typeid(*this).name());
}
Run Code Online (Sandbox Code Playgroud)

是的,在任何人指出它之前,我意识到输出typeinfo::name是特定于实现的.

根据MSDN

所述type_info::name成员函数返回一个const char*到表示该类型的人类可读名称的空终止字符串.指向的内存是缓存的,永远不应该直接释放.

但是,当我在调试器中退出程序时,任何"新"使用都会typeinfo::name()显示为内存泄漏.如果我输出2个类的信息,我会得到2个内存泄漏,依此类推.这暗示缓存的数据永远不会被释放.

虽然这不是一个主要问题,但它看起来很混乱,经过长时间的调试后,它可以很容易地隐藏真正的内存泄漏.

我环顾四周,发现了一些有用的信息(一个SO答案给出了一些有关如何实现typeinfo的有趣信息),但我想知道这个内存是否应该被系统释放,或者我是否可以做些什么来解决调试时"不注意"泄漏.

我确实有一个备份计划,即getMessageName自己编写方法并不依赖typeinfo::name,但无论如何我想知道是否有我错过的东西.

小智 4

另一种解决方案是纠正根本问题。这并不是真正的内存泄漏,只是一个错误的报告。分配给 typeinfo() 和 name() 字符串的内存块被分配了错误的块类型。“释放”该内存可能不是一个好主意,因为 CRT 将尝试再次释放它。好消息是这个问题最终在 VS2012 (_MSC_VER 1700+) 中得到修复。

由于这仅适用于 _DEBUG 构建,因此以下可能是更安全的解决方案。函数 _FixTypeInfoBlockUse() 应在退出模块入口点(main、WinMain 等)之前按上述方法调用。

#if defined(_DEBUG) && (_MSC_VER >= 1000 && _MSC_VER <= 1699)
//
// Debug memory block header:
//    o  Borrowed from the Microsoft CRT to fix the false "memory leak" report
//       when using typeinfo 'name' accessor in a _DEBUG build of the library.  
//
struct _CrtMemBlockHeader
   {
   struct _CrtMemBlockHeader * pBlockHeaderNext;
   struct _CrtMemBlockHeader * pBlockHeaderPrev;
   char *                      szFileName;
   int                         nLine;
   #ifdef _WIN64
   int                         nBlockUse;
   size_t                      nDataSize;
   #else
   size_t                      nDataSize;
   int                         nBlockUse;
   #endif
   long                        lRequest;
   unsigned char               gap[4];
   };

static void __cdecl _FixTypeInfoBlockUse(void)
   {
   __type_info_node* pNode = __type_info_root_node._Next;

   while(pNode != NULL)
      {
      __type_info_node* pNext = pNode->_Next;

      (((_CrtMemBlockHeader*)pNode) - 1)->nBlockUse = _CRT_BLOCK;

      if (pNode->_MemPtr != NULL)
         (((_CrtMemBlockHeader*)pNode->_MemPtr) - 1)->nBlockUse = _CRT_BLOCK;

      pNode = pNext;
      }
   }

#endif//defined(_DEBUG) && (_MSC_VER >= 1000 && _MSC_VER <= 1699)
Run Code Online (Sandbox Code Playgroud)