OSG学习:OSG中的智能指针
发布日期:2025-05-01 06:15:15 浏览次数:2 分类:技术文章

本文共 2213 字,大约阅读时间需要 7 分钟。

转载自:

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

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

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

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

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

[cpp]   
  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]   
  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]   
  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]   
  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. }  

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

上一篇:OSG学习:OSG组成(一)——组成模块
下一篇:OSG学习:C#调用非托管C++方法——C++/CLI

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2025年04月23日 14时38分01秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章