首页 > 代码库 > OSG 智能指针陷阱

OSG 智能指针陷阱


先看下这个代码,有什么问题:

#include <osg/Group>
#include <osg/Node>
#include <osg/Geode>

osg::Geode *geode= NULL;
osg::ref_ptr<osg::Group> root = NULL;

void createNode(){
	geode = new osg::Geode;
	geode->setName("Hello");
	root = new osg::Group;
	root->addChild(geode);
}
void GetNodeFromRoot(osg::Node ** node){

	for(int i = 0; i<root->getNumChildren(); ++i)
	{
		if(root->getChild(i)->getName().compare("Hello") == 0)
		{
			osg::Node * tmp = root->getChild(i);
			root->removeChild(tmp);
			*node = tmp;//在这里tmp 已经析构,因为 只有root引用了hello节点,而在root 节点removechild后 tmp的引用计数为0,此时将析构
		}
	}
}

int main()
{ 
	createNode();
	osg::Node * node = NULL;
	GetNodeFromRoot(&node);
}

所以在最后得到的这个指针是个无效的指针。


正确的方法应该是:

void GetNodeFromRoot(osg::ref_ptr<osg::Node> & node)
{
	for(int i = 0; i<root->getNumChildren(); ++i)
	{
		if(root->getChild(i)->getName().compare("Hello") == 0)
		{
			osg::Node * tmp = root->getChild(i);
			node = tmp;//要先让node对象对hello节点引用
			root->removeChild(tmp);			
		}
	}
}

还有一种情况容易出问题:

#include <osg/Group>
#include <osg/Node>
#include <osg/Geode>

int main()
{ 
	osg::Geode * geode = new osg::Geode;
	int num = geode->referenceCount();//num 应该为0
	{
		osg::ref_ptr<osg::Group> root =new	osg::Group;
		root->addChild(geode);
		 num = geode->referenceCount();//num 应该为1 
	}
	 num = geode->referenceCount();//num 应该为 无效数字,因为此时geode已经析构 

	 return 0;
}

另一种常见的错误为  直接返回智能指针对象:

osg::Node * getNode()
{
	osg::ref_ptr<osg::Geode> geode = new osg::Geode;

	return geode;//错误,应该为geode.release();
}


总结:

1. 在osg::ref_ptr<osg::Node>node = new osg::Node;  其中node 为osg::ref_ptr的对象,而不是指针。

2. OSG 中新创建的场景对象建议使用ref_ptr 进行内存分配和管理

3. 对于不使用ref_ptr 的对象,引用计数值变得没有意义,并且它无法自动从场景中卸载。

4. 新建对象作为函数结果返回时,应该返回release()。并尽快引入到别的场景中,否则发生内存泄露