转载自:OSG中的智能指针
OSG中使用了智能指针,对堆内存进行管理。
智能指针,其实就是在原始指针的基础上,加上了一个引用计数,然后通过引用计数的值,来决定什么时候释放内存。其目标就是确保一段内存会被释放,且只被释放一次。
OSG中的引用计数,存放在osg::Referenced类中,然后这个类提供了对引用计数进行增加的函数Referenced::ref(), 以及对引用计数进行减少的函数Referenced::unref()。这个类只提供了引用计数的基本操作。所有继承自osg::Referenced的类,它里面都有一个引用计数。
但是什么时候增加引用计数,什么时候减少引用计数,则是通过ref_ptr来进行管理的。当一个内存块被new出来之后,只要它将这个内存块指针交给ref_ptr进行管理,程序就不需要考虑什么时候释放这个内存块了。
下面的代码存在问题,在root->removeChild的时候,cow这个内存块已经被释放了。此时再把cow加到场景中,问题就出来了,因为这个内存已经被释放了。
- #include <osg/ref_ptr>
- #include<osgViewer/Viewer>
- #include <osgDB/ReadFile>
- #include <osg/Node>
- int main(int argc, char **argv)
- {
- osgViewer::Viewer viewer;
- osg::Node* cow = osgDB::readNodeFile("cow.osg");
- osg::Group* root = new osg::Group;
- root->addChild(cow);
- root->removeChild(cow);
- viewer.setSceneData(cow);
- return viewer.run();
- }
- #include <osg/ref_ptr>
- #include<osgViewer/Viewer>
- #include <osgDB/ReadFile>
- #include <osg/Node>
- int main(int argc, char **argv)
- {
- osgViewer::Viewer viewer;
- osg::ref_ptr<osg::Node> cow = osgDB::readNodeFile("cow.osg");
- osg::Group* root = new osg::Group;
- root->addChild(cow);
- root->removeChild(cow);
- viewer.setSceneData(cow);
- return viewer.run();
- }
所以在OSG中,只管new对象,new完之后,交给ref_ptr进行管理即可。所有继承自Referenced的类,都支持ref_ptr进行管理,因为它们自身都有一个引用计数。
但是有一点例外,如果是通过函数创建对象,创建完了之后,需要返回该对象的内存,在函数内部,则不应该把这个内存交给智能指针去管。比如
- #include <osg/ref_ptr>
- #include<osgViewer/Viewer>
- #include <osgDB/ReadFile>
- osg::Node* createCowNode()
- {
- osg::ref_ptr<osg::Node> cow = osgDB::readNodeFile("cow.osg");
- return cow.get();
- }
- int main(int argc, char **argv)
- {
- osgViewer::Viewer viewer;
- viewer.setSceneData(createCowNode());
- return viewer.run();
- }
这块内存虽然交给了智能指针处理,但是它的处理方式与我们想象的不一样。这个和返回局部对象的指针那种情况一样了。
正确的做法是函数返回之后,再对内存使用智能指针进行管理,像下面这样
- #include <osg/ref_ptr>
- #include<osgViewer/Viewer>
- #include <osgDB/ReadFile>
- osg::Node* createCowNode()
- {
- return osgDB::readNodeFile("cow.osg");
- }
- int main(int argc, char **argv)
- {
- osgViewer::Viewer viewer;
- osg::ref_ptr<osg::Node> cow = createCowNode();
- viewer.setSceneData(cow.get());
- return viewer.run();
- }
综上所述,创建的内存块,交给智能指针进行管理,也还是需要考虑智能指针它本身的作用域和生命周期。因为智能指针它自己本身是位于栈上的,它管理的内存块位于堆上。