鱼C论坛

 找回密码
 立即注册
查看: 2367|回复: 1

[技术交流] 跟踪内存泄漏

[复制链接]
发表于 2014-2-23 14:35:26 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 andalousie 于 2014-2-25 08:41 编辑

我在书上看到可以通过重载new和delete运算符实现跟踪内存泄漏。这里把我自己的例子发布出来。
用于测试的文件test.cpp
#include <iostream>
#include <cstdlib>
#if !defined NDEBUG
#include "Tracer.h"
#define new new (__FILE__, __LINE__)
Tracer NewTrace;
#endif
#include <cstring>
/************************************************
* info -- A class to hold information.         *
*                                              *
* Note:                                        *
*      Because someone is walking all over our *
*      memory and destroying our data, we      *
*      have put two guards at the beginning    *
*      and end of our class.    If someone     *
*      messes with us these numbers will       *
*      be destroyed.                           *
*                                              *
* Member functions:                            *
*      set_data -- Store a string in our data. *
*      get_data -- Get the data string. *
*      check_magic -- Check the magic numbers. *
************************************************/
// Magic numbers for the start and end of the
// data in the class info
const int START_MAGIC = 0x11223344;
const int END_MAGIC = 0x5567788;
class info
{
    private:
        // Magic protection constant
        const int start_magic;
        // String to be stored
        char data[30];
        // Magic protection constant
        const int end_magic;
    public:
        info(void):
            start_magic(START_MAGIC),
            end_magic(END_MAGIC)
            {}
        // Copy constructor defaults
        // Assignment operator defaults
        // Destructor defaults
        // Store some data in the class
        void set_data(
            // Data to be stored
            const char what[]
        )
        {
            strcpy(data, what);
        }
        // Get the data from the class
        char *get_data(void)
        {
            return (data);
        }
        // Verify that the magic
        // numbers are correct
        void check_magic(void)
        {
            if ((start_magic != START_MAGIC) ||
                (end_magic != END_MAGIC))
            {
                std::cout <<
                    "Info has lost its magic\n";
            }
        }
};
/************************************************
* new_info -- Create a new version of the      *
*      info class.                             *
************************************************/
struct info *new_info(void)
{
    struct info *result; // Newly created result.
/*    result = (struct info *)
        malloc(sizeof(struct info));
    // Make sure the structure is clear
    memset(result, '\0',  sizeof(result));*/
    result = new info;  // Use C++ new rather than C malloc
    return (result);
}
int main()
{
    // An info class to play with
    class info *a_info = new_info();
    a_info->set_data("Data");
    a_info->check_magic();
    return (0);
}
测试结果
  1. *** Memory leak(s)
  2. 0x11223344: ptr/main.cpp, line 82
复制代码
通过测试发现,在代码的第82行,也就是红色字体的,内存没有被释放。
这个代码本来是一个教学代码,如果使用绿色字体部分,而不是红色字体部分,就会输出
Info has lost its magic()
原因很简单,我们使用C语言形式的malloc分配空间不会调用构造函数,然后雪上加霜地用memset来将类置0……
对于这种问题,我只能给出一个我认为还算过得去的方案,就是使用智能指针。
我们可以自己写一个auto_ptr类,来用析构函数实现其内容的销毁。
  1. #if !defined (AUTOPTR_H)
  2. #define AUTOPTR_H

  3. //-------------
  4. // Auto pointer
  5. //-------------
  6. template<class T>
  7. class auto_ptr
  8. {
  9.         template<class U> struct auto_ptr_ref
  10.         {
  11.                 auto_ptr<U> & _ap;
  12.                 auto_ptr_ref (auto_ptr<U> & p) : _ap (p) {}
  13.         };
  14. public:
  15.         typedef T element_type;

  16.         explicit auto_ptr (T * p = 0) : _p (p) {}

  17.         // "transfer" constructor
  18.         auto_ptr (auto_ptr & pSrc)
  19.         {
  20.                 _p = pSrc._p;
  21.                 pSrc._p = 0;
  22.         }

  23.         auto_ptr & operator= (auto_ptr & pSrc)
  24.         {
  25.                 reset (pSrc.release ());
  26.                 return *this;
  27.         }
  28. #if 0 // not in this version of the compiler
  29.         // "transfer" from derived class
  30.         template<class U>
  31.         auto_ptr (auto_ptr<U> & pSrc)
  32.         {
  33.                 _p = pSrc._p; // implicit cast
  34.                 pSrc._p = 0;
  35.         }

  36.         // assignment of derived class
  37.         template<class U>
  38.         auto_ptr & operator= (auto_ptr<U> & pSrc)
  39.         {
  40.                 if (this != &pSrc)
  41.                 {
  42.                         _p = pSrc._p;
  43.                         pSrc._p = 0;
  44.                 }
  45.                 return *this;
  46.         }
  47. #endif
  48.         ~auto_ptr () { delete _p; }

  49.         T & operator* () const { return *_p; }

  50.         T * operator-> () const { return _p; }

  51.         T * get () const { return _p; }

  52.         T * release ()
  53.         {
  54.                 T * tmp = _p;
  55.                 _p = 0;
  56.                 return tmp;
  57.         }

  58.         void reset (T * p = 0)
  59.         {
  60.                 if (p != _p)
  61.                 {
  62.                         delete _p;
  63.                         _p = p;
  64.                 }
  65.         }

  66.         auto_ptr (auto_ptr_ref<T> apr)
  67.                 : _p (apr._ap.release ())
  68.         {}

  69.         template<class U>
  70.         operator auto_ptr_ref<U> ()
  71.         {
  72.                 return auto_ptr_ref<U> (*this);
  73.         }

  74.         template<class U>
  75.         operator auto_ptr<U> ()
  76.         {
  77.                 return auto_ptr<U> (release ());
  78.         }
  79. private:
  80.         T * _p;
  81. };

  82. #endif
复制代码
而把结构体的内容改成
  1. struct info *new_info(void)
  2. {
  3.     auto_ptr<info> result(new info);
  4.     return (result.release());
  5. }
复制代码
在return之后就会自动调用auto_ptr类的析构函数。至于形参new info,其实在使用以后系统就会将其释放,所以我认为没有影响。或者大家以可以使用<memory>头文件里面的std::auto_ptr,这样就用不着自己写了。
如果有其他好的解决方案,请回复。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2014-2-25 00:35:10 | 显示全部楼层
难度好大 啊
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-18 18:03

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表