[C++]野指针的产生以及应对办法

很大程度上,野指针都是因为编码不善,习惯不好所产生的.

要解决野指针,就要养成好习惯,不要动不动就public数据成员,所有的数据访问都抽象成接口,最好只在一个地方delete数据.

前段时间游戏技术测试,down机无限,搞的很头疼.后来用valgrind的memcheck工具,找到很多野指针.

valgrind很好用,除了有一点慢:-)

valgrind --tool=memcheck --leak-check=full --log-file=./log_file.log --showpossibly-lost=no --malloc-fill=0xff --free-fill=0x11 ./execFile

用上面的语句,就可以启动一个execFile,顺便把所有malloc内存设置成0xff,free内存设置成0x11,还会统计内存泄露(在log_file.log内).简单易用.

然后么,一个一个去fix....

跟同学交流,他们那边有一个办法,去解决这个野指针问题,也是很巧妙的,不敢独享:-D

A对象会被n个其他对象B引用,就是其他n个对象B会持有指向A的指针.

如果A被delete,其他n个对象B指向A的指针的内存已经不可访问,这个时候访问那块内存,就会发生未定义行为.

天知道会怎么样!!!也许会down掉,也许不会.

他们是搞的:

1) 对象B对A的引用,A自己会保存一份记录,标记有对象B引用过自己

2) 对象B析构,会通知A,这个时候,A会去除B对自己的引用的标记

3) A析构,A会把所有指向自己的指针,设置成NULL

这是基本思想.

下面给出简单的实现,非线程安全,有什么问题可以提出...

#ifndef __REFERABLE_H__
#define __REFERABLE_H__

#include <vector>
#include "ref_ptr.h"

template<typename T>
class referable
{
public:    
    typedef referable** RefAddress;
    virtual ~referable()
    {
        for (container_iter iter = m_references.begin();
            iter != m_references.end();
            ++iter)
        {
            **iter = NULL; 
        }
    }
private:
    typedef typename std::vector<RefAddress> container_type;
    typedef typename container_type::iterator container_iter;

    friend class ref_ptr<T>;
    void on_reg(RefAddress addr)
    {
        for (container_iter iter = m_references.begin();
            iter != m_references.end();
            ++iter)
        {
            if(*iter == addr) return;
        }
        m_references.push_back(addr);
    }
    void on_unreg(RefAddress addr)
    {
        for (container_iter iter = m_references.begin();
            iter != m_references.end();)
        {
            if(*iter == addr)
                iter = m_references.erase(iter);
            else
                ++iter;
        }
    }
private:
    container_type m_references;
};
#endif
#ifndef __REFERENCE_POINTER_H__
#define __REFERENCE_POINTER_H__
#include "referable.h"

template<typename T>
class ref_ptr
{
public:
    ref_ptr():m_ptr(NULL){}
    ref_ptr(T *ptr):m_ptr(ptr)
    {
        add_ref();
    }
    ref_ptr(const ref_ptr<T>& ref):m_ptr(ref.m_ptr)
    {
        add_ref();
    }
    virtual ~ref_ptr()
    {
        remove_ref();
    }

    ref_ptr<T>& operator = (const ref_ptr<T>& ref)
    {
        if(this == &ref) return *this;
        remove_ref();
        m_ptr = ref.m_ptr;
        add_ref();
        return *this;
    }
    ref_ptr<T>& operator = (T *ptr)
    {
        if(m_ptr != ptr)
        {
            remove_ref();
            m_ptr = ptr;
            add_ref();
        }
        return *this;
    }
public:
    T*  operator->() const { return m_ptr; }
    T&  operator*() const { return *m_ptr; }
    operator T*() const { return m_ptr; }
    operator bool() const { return m_ptr; }
private:
    void add_ref()
    {
        if(m_ptr) ((referable<T>*)m_ptr)->on_reg((referable<T>**)&m_ptr);
    }
    void remove_ref()
    {
        if(m_ptr) ((referable<T>*)m_ptr)->on_unreg((referable<T>**)&m_ptr);
        m_ptr = NULL;
    }

private:
    T* m_ptr;
};

#endif

测试代码:

class object : public referable<object>
{
public:
    int x;
};

void test()
{
    object *a = new object;
    object *a1 = new object;
    ref_ptr<object> b = a;
    a->x = 10;
    assert(b && b->x == 10);

    delete a;
    assert(!b);

    b = a1;
    assert(b);
}

这个东西看上去还不错.

不过习惯还是很重要滴

PS:

一般引用都是只有四五个,所以vector性能足够好,我测试过~~

原文链接: https://www.cnblogs.com/egmkang/archive/2011/09/26/2189548.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    [C++]野指针的产生以及应对办法

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/33105

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月8日 上午10:11
下一篇 2023年2月8日 上午10:14

相关推荐