鱼C论坛

 找回密码
 立即注册
查看: 1831|回复: 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);
}
测试结果
*** Memory leak(s)
0x11223344: ptr/main.cpp, line 82
通过测试发现,在代码的第82行,也就是红色字体的,内存没有被释放。
这个代码本来是一个教学代码,如果使用绿色字体部分,而不是红色字体部分,就会输出
Info has lost its magic()
原因很简单,我们使用C语言形式的malloc分配空间不会调用构造函数,然后雪上加霜地用memset来将类置0……
对于这种问题,我只能给出一个我认为还算过得去的方案,就是使用智能指针。
我们可以自己写一个auto_ptr类,来用析构函数实现其内容的销毁。
#if !defined (AUTOPTR_H)
#define AUTOPTR_H

//-------------
// Auto pointer
//-------------
template<class T>
class auto_ptr
{
        template<class U> struct auto_ptr_ref
        {
                auto_ptr<U> & _ap;
                auto_ptr_ref (auto_ptr<U> & p) : _ap (p) {}
        };
public:
        typedef T element_type;

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

        // "transfer" constructor
        auto_ptr (auto_ptr & pSrc)
        {
                _p = pSrc._p;
                pSrc._p = 0;
        }

        auto_ptr & operator= (auto_ptr & pSrc)
        {
                reset (pSrc.release ());
                return *this;
        }
#if 0 // not in this version of the compiler
        // "transfer" from derived class
        template<class U> 
        auto_ptr (auto_ptr<U> & pSrc)
        {
                _p = pSrc._p; // implicit cast
                pSrc._p = 0;
        }

        // assignment of derived class
        template<class U> 
        auto_ptr & operator= (auto_ptr<U> & pSrc)
        {
                if (this != &pSrc)
                {
                        _p = pSrc._p;
                        pSrc._p = 0;
                }
                return *this;
        }
#endif
        ~auto_ptr () { delete _p; }

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

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

        T * get () const { return _p; }

        T * release ()
        {
                T * tmp = _p;
                _p = 0;
                return tmp;
        }

        void reset (T * p = 0)
        {
                if (p != _p)
                {
                        delete _p;
                        _p = p;
                }
        }

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

        template<class U>
        operator auto_ptr_ref<U> ()
        {
                return auto_ptr_ref<U> (*this);
        }

        template<class U>
        operator auto_ptr<U> ()
        {
                return auto_ptr<U> (release ());
        }
private:
        T * _p;
};

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

使用道具 举报

发表于 2014-2-25 00:35:10 | 显示全部楼层
难度好大 啊
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-12-24 10:29

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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