OSG学习:OSG中的智能指针

转载自:OSG中的智能指针

OSG中使用了智能指针,对堆内存进行管理。 

智能指针,其实就是在原始指针的基础上,加上了一个引用计数,然后通过引用计数的值,来决定什么时候释放内存。其目标就是确保一段内存会被释放,且只被释放一次。


OSG中的引用计数,存放在osg::Referenced类中,然后这个类提供了对引用计数进行增加的函数Referenced::ref(), 以及对引用计数进行减少的函数Referenced::unref()。这个类只提供了引用计数的基本操作。所有继承自osg::Referenced的类,它里面都有一个引用计数。


但是什么时候增加引用计数,什么时候减少引用计数,则是通过ref_ptr来进行管理的。当一个内存块被new出来之后,只要它将这个内存块指针交给ref_ptr进行管理,程序就不需要考虑什么时候释放这个内存块了。


下面的代码存在问题,在root->removeChild的时候,cow这个内存块已经被释放了。此时再把cow加到场景中,问题就出来了,因为这个内存已经被释放了。

[cpp]  view plain  copy
  1. #include <osg/ref_ptr>  
  2. #include<osgViewer/Viewer>  
  3. #include <osgDB/ReadFile>  
  4. #include <osg/Node>  
  5.   
  6.   
  7. int main(int argc, char **argv)  
  8. {  
  9.     osgViewer::Viewer viewer;  
  10.   
  11.     osg::Node* cow = osgDB::readNodeFile("cow.osg");  
  12.     osg::Group* root = new osg::Group;  
  13.     root->addChild(cow);  
  14.     root->removeChild(cow);  
  15.     viewer.setSceneData(cow);  
  16.   
  17.     return viewer.run();  
  18. }  


但是如果readNodeFile返回的内存,交给ref_ptr进行管理,则不会出现问题,如下所示。

[cpp]  view plain  copy
  1. #include <osg/ref_ptr>  
  2. #include<osgViewer/Viewer>  
  3. #include <osgDB/ReadFile>  
  4. #include <osg/Node>  
  5.   
  6. int main(int argc, char **argv)  
  7. {  
  8.     osgViewer::Viewer viewer;  
  9.   
  10.     osg::ref_ptr<osg::Node> cow = osgDB::readNodeFile("cow.osg");  
  11.     osg::Group* root = new osg::Group;  
  12.     root->addChild(cow);  
  13.     root->removeChild(cow);  
  14.     viewer.setSceneData(cow);  
  15.   
  16.     return viewer.run();  
  17. }  

所以在OSG中,只管new对象,new完之后,交给ref_ptr进行管理即可。所有继承自Referenced的类,都支持ref_ptr进行管理,因为它们自身都有一个引用计数。


但是有一点例外,如果是通过函数创建对象,创建完了之后,需要返回该对象的内存,在函数内部,则不应该把这个内存交给智能指针去管。比如

[cpp]  view plain  copy
  1. #include <osg/ref_ptr>  
  2. #include<osgViewer/Viewer>  
  3. #include <osgDB/ReadFile>  
  4.   
  5. osg::Node* createCowNode()  
  6. {  
  7.     osg::ref_ptr<osg::Node> cow = osgDB::readNodeFile("cow.osg");  
  8.     return cow.get();  
  9. }  
  10.   
  11. int main(int argc, char **argv)  
  12. {  
  13.     osgViewer::Viewer viewer;  
  14.     viewer.setSceneData(createCowNode());  
  15.     return viewer.run();  
  16. }  
上面的代码存在问题,因为智能指针cow以为你离开createCowNode之后,就不需要这个cow所指的内存,它把这块内存给删了,所以导致程序访问出错。

这块内存虽然交给了智能指针处理,但是它的处理方式与我们想象的不一样。这个和返回局部对象的指针那种情况一样了。

正确的做法是函数返回之后,再对内存使用智能指针进行管理,像下面这样

[cpp]  view plain  copy
  1. #include <osg/ref_ptr>  
  2. #include<osgViewer/Viewer>  
  3. #include <osgDB/ReadFile>  
  4.   
  5. osg::Node* createCowNode()  
  6. {  
  7.     return osgDB::readNodeFile("cow.osg");  
  8. }  
  9.   
  10. int main(int argc, char **argv)  
  11. {  
  12.     osgViewer::Viewer viewer;  
  13.     osg::ref_ptr<osg::Node> cow = createCowNode();  
  14.     viewer.setSceneData(cow.get());  
  15.     return viewer.run();  
  16. }  

综上所述,创建的内存块,交给智能指针进行管理,也还是需要考虑智能指针它本身的作用域和生命周期。因为智能指针它自己本身是位于栈上的,它管理的内存块位于堆上。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值