一.简介
OSG提供了一种自动管理内存的机制,这种机制涉及到两个类:osg::ref_ptr类 和 osg::Referenced类
二.osg::Reference类
osg::Reference类实现了对内存区段的引用计数器功能。
所有的OSG的节点和场景图形数据(状态信息 顶点数组 法线 纹理坐标)都派生于Referenced类进行内存引用计数
Referenced类有3个主要组成部分:
1.保护成员整型变量_refCount,用作引用计数,在构造时被初始化为0
2.公有函数ref()和unref(),用于实现_refCount值得增加和减少,当_refCount为0时,unref()将自动释放该对象所占用的内存
3.作为保护成员存在的虚析构函数
1.类定义
class OSG_EXPORT Referenced { public: Referenced(); explicit Referenced(bool threadSafeRefUnref); Referenced(const Referenced&); inline Referenced& operator = (const Referenced&) {return *this;} virtual void setThreadSafeRefUnref(bool threadSafe); #if defined (_OSG_REFERENCED_USE_ATOMIC_OPERATIONS) bool getThreadSafeRefUnref() const {return true;} #else bool getThreadSafeRefUnref() const {return _refMutex != 0;} #endif #if defined (_OSG_REFERENCED_USE_ATOMIC_OPERATIONS) OpenThreads::Mutex* getRefMutex() const {return getGlobalReferencedMutex();} #else OpenThreads:: }
三.osg::ref_ptr类
osg::ref_ptr类用于实现一个指向Referenced对象的智能指针,并对其引用计数器进行管理
osg::ref_ptr<>模板类包含了3个主要组成部分:
1.一个私有指针_ptr,用于保存管理内存区域的地址,可以用get()方法返回_ptr的值
2.类似指针重载定义了方法
3.valid()方法,用于判断ref_ptr<>是否为空,不为NULL时返回true
osg::ref_ptr<osg::类> 对象 = new osg::类;
1.类定义
template<class T> class ref_ptr { public:
typedef T element_type;
ref_ptr() : _ptr(0) {}
ref_ptr(T* ptr) : _ptr(ptr) {if(_ptr) _ptr->ref();}
ref_ptr(const ref_ptr& rp) : _ptr(rp.ptr) {if(_ptr) _ptr->ref();}
template<class Other> ref_ptr(const ref_ptr<Other>& rp) : _ptr(rp._ptr) {if(_ptr) _ptr->ref();}
ref_ptr(observer_ptr<T>& optr) : _ptr(0) {optr.lock(*this);}
~ref_ptr() {if(_ptr) _ptr->unref(); _ptr = 0;}
ref_ptr& operator = (const ref_ptr& rp)
{
assign(rp);
return *this;
}
template<class Other> ref_ptr& operator = (const ref_ptr<Other>& rp)
{
assign(rp);
return *this;
}
inline ref_ptr& operator = (T* ptr)
{
if (_ptr==ptr) return *this;
T* tmp_ptr = _ptr;
_ptr = ptr;
if (_ptr) _ptr->ref();
if(tmp_ptr) tmp_ptr->unref();
return *this;
}
#ifdef OSG_USE_REF_PTR_IMPLICIT_OUTPUT_CONVERSION
operator T*() const {return _ptr;}
#else
bool operator == (const ref_ptr& rp) const {return (_ptr == rp._ptr);}
bool operator == (const T* ptr) const {return (_ptr == ptr);}
friend bool operator == (const T* ptr, const ref_ptr& rp) {return (ptr == rp.ptr)}
bool operator != (const ref_ptr& rp) const {return (_ptr != rp._ptr);}
bool operator != (const T* ptr) const {return (_ptr != ptr);}
friend bool operator != (const T* ptr, const ref_ptr& rp) {return (ptr != rp._ptr);}
bool operator < (const ref_ptr& rp) const {return (_ptr < rp._ptr);}
private:
typedef T* ref_ptr::*unspecified_bool _type;
public:
operator unspecified_bool_type() const {return valid() ? &ref_ptr::_ptr : 0;}
#endif
T& operator* () const {return *_ptr;}
T* operator->() const {return _ptr;}
//获取指针
T* get() const {return _ptr;}
bool operator !() const {return _ptr == 0;}
bool valid() const {return _ptr != 0;}
//返回指针
T* release() {T* tmp = _ptr; if (_ptr) _ptr->unref_nodelete(); _ptr = 0; return tmp;}
void swap(ref_ptr& rp) {T* tmp = _ptr; _ptr = rp._ptr; rp._ptr = tmp;}
private:
template<class Other> void assign(const ref_ptr<Other>& rp)
{
if (_ptr == rp._ptr) return;
T* tmp_ptr = _ptr;
_ptr = rp._ptr;
if (_ptr) _ptr->ref();
if (tmp_ptr) tmp_ptr->unref();
}
template<class Other> friend class ref_ptr;
T* _ptr; };
2.使用 osg::ref_ptr<>
osg::ref_ptr<osg::Geode> geodePtr = new osg::Geode(); osg::Geode* obj1 = * geodePtr; //获取Geode指针 osg::Geode* obj2 = geodePtr.get(); //获取Geode指针
//作为返回值
osg::Geode* createGeode()
{
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
return geode.release();
}
四.使用智能指针
在osg中,大多数场景图形类都继承自osg::Reference,但也有注意的地方
1.使用智能指针模板的类必须继承自osg::Reference类,否则无法使用
2.在创建智能指针之后,不能手动调动delete来删除该智能指针,否则编译会提示错误信息。因为osg::Reference的析构函数是保护类型
3.在osg::Reference类成员函数中,有两个共有的成员函数ref() 和 unref(),它们主要是用来控制内存计数器,不要随意使用来改变内存计数器的值
4.在osg中,可以new运算指针
每个类要使用之前先用智能指针托管,用于避免内存泄漏
bool CPickHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) { osg::ref_ptr<osg::Group> root = new osg::Group;
osg::ref_ptr<osg::Geode> node1 = new osg::Geode;
osg::ref_ptr<osg::Geometry> geo1 = new osg::Geometry;
root->addChild(node1.get());
node1->addDrawable(geo1.get());
printf("%d, %d, %d", root->referenceCount(), node1->referenceCount(), geo1->referenceCount()); }
五.dynamic_cast
dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换
在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。