zoukankan      html  css  js  c++  java
  • [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性能足够好,我测试过~~

  • 相关阅读:
    java Activiti 工作流引擎 SSM 框架模块设计方案
    自定义表单 Flowable 工作流 Springboot vue.js 前后分离 跨域 有代码生成器
    数据库设计的十个最佳实践
    activiti 汉化 stencilset.json 文件内容
    JAVA oa 办公系统模块 设计方案
    java 考试系统 在线学习 视频直播 人脸识别 springboot框架 前后分离 PC和手机端
    集成 nacos注册中心配置使用
    “感恩节 ”怼记
    仓颉编程语言的一点期望
    关于System.out.println()与System.out.print("\n")的区别
  • 原文地址:https://www.cnblogs.com/egmkang/p/2189548.html
Copyright © 2011-2022 走看看