很大程度上,野指针都是因为编码不善,习惯不好所产生的.
要解决野指针,就要养成好习惯,不要动不动就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#include "ref_ptr.h" template 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 container_type; typedef typename container_type::iterator container_iter; friend class ref_ptr ; 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" templateclass ref_ptr { public: ref_ptr():m_ptr(NULL){} ref_ptr(T *ptr):m_ptr(ptr) { add_ref(); } ref_ptr(const ref_ptr & ref):m_ptr(ref.m_ptr) { add_ref(); } virtual ~ref_ptr() { remove_ref(); } ref_ptr & operator = (const ref_ptr & ref) { if(this == &ref) return *this; remove_ref(); m_ptr = ref.m_ptr; add_ref(); return *this; } ref_ptr & 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 *)m_ptr)->on_reg((referable **)&m_ptr); } void remove_ref() { if(m_ptr) ((referable *)m_ptr)->on_unreg((referable **)&m_ptr); m_ptr = NULL; } private: T* m_ptr; }; #endif
测试代码:
class object : public referable
这个东西看上去还不错.
不过习惯还是很重要滴
PS:
一般引用都是只有四五个,所以vector性能足够好,我测试过~~