关于OSG智能指针 osg::ref_ptr 的一些测试

OSG很久了,但本来编程就比较渣渣,看的书也比较少,所以,对这个新事物的理解总不是那么深刻。近日看到一篇博文《OSG 智能指针陷阱 总结》,发现博文中有很多问题,特在此把自己的测试及感想分享给同是渣渣的你。


本文的代码是按照《OSG 智能指针陷阱 总结》改编来进行测试的,可以对比来看。

正文:

首先,我对智能指针的理解是,智能指针是对本节点被引用次数进行计数的,也就是初始化后计数为1,代表被自身引用一次。继承自osg::Referenced的类的实例均可以进行引用计数。还有,不管是否声明为智能指针对象,该对象被引用后计数都会增加,而不论是被智能指针还是普通指针所用。(之所以这样说,是因为我觉得他对智能指针的理解有问题)

其次,输出节点的name,只是为了断定该节点是否依然有效。

问题1:

下面这段代码是我按照他第一个问题的解决方法改变来的:

#include 
#include 
#include 
#include 
#include 

#include 

// osg::ref_ptr rnode = NULL;
// osg::Group* root = NULL;

osg::Node *rnode = NULL;
osg::ref_ptr root = NULL;

// osg::Node *rnode = NULL;
// osg::Group *root = NULL;

void createNode(){
	rnode = osgDB::readNodeFile("lz.osg");
	rnode->setName("Hello");
	root = new osg::Group;
	root->addChild(rnode);
}
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);
			
			std::cout << rnode->getName() << tmp->getName() << rnode->referenceCount() << std::endl;
			//root->removeChild(tmp);
			//std::cout << rnode->getName() << tmp->getName() << rnode->referenceCount() << std::endl;
			*node = tmp;
			root->removeChild(tmp);
			std::cout << rnode->getName() << tmp->getName() << rnode->referenceCount() << std::endl;
		}
	}
}

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

	osg::Group* group = new osg::Group;
	group->addChild(node);

	osgViewer::Viewer viewer;
	viewer.setSceneData(group);

	return viewer.run();
}
按照他的意思,这个应该是没问题的,先引用,后删除tmp。但实际上我们并没有运行过去。
从控制台的输出来看:
HelloHello1
0
第一次输出没有任何问题,但第二次显然没有输出节点的名字,我想是因为rnode是个普通指针,进行root->removeChild(tmp);操作之后,其内存已经被释放,所以无法输出名字。既然这样,那么加入场景后必然出错。
解决方法:
把rnode定义成智能指针对象,即:
osg::ref_ptr rnode = NULL;

现在运行没问题了吧,控制台输出如下:
HelloHello2
HelloHello1
解释:第一次输出计数为2,因为初始化后rnode本身计数为1,加入到root中后,计数加1,为2;当root->removeChild(tmp);,计数减1,为1。

问题2:

int main()
{
	osg::ref_ptr node = osgDB::readNodeFile("glider.osg");
	//osg::Node * node = osgDB::readNodeFile("glider.osg");
	node->setName("glider");
	std::cout << node->getName() << node->referenceCount() << std::endl;

	{
		osg::ref_ptr root = new	osg::Group;
		root->addChild(node);
		std::cout << node->getName() << node->referenceCount() << std::endl;
	}
	//如果使用的是osg::Node *,那么node在这个上个循环结束之前已经被析构。
	std::cout << node->getName() << node->referenceCount() << std::endl;

	{
		osg::ref_ptr root = new	osg::Group;
		root->addChild(node);
		osg::ref_ptr root2 = new	osg::Group;
		root2->addChild(node);
		osg::ref_ptr root3 = new	osg::Group;
		root3->addChild(node);
		std::cout << node->getName() << node->referenceCount() << std::endl;
		root->removeChild(node);
		std::cout << node->getName() << node->referenceCount() << std::endl;
	}
	std::cout << node->getName() << node->referenceCount() << std::endl;

	{
		osg::Group* root = new	osg::Group;
		root->addChild(node);
		//root->addChild(node);
		osg::Group* root2 = new	osg::Group;
		root2->setName("root2");
		root2->addChild(node);
		std::cout << node->getName() << node->referenceCount() << std::endl;

		//error ~Group() Protected Member Functions
		//delete root;
	}
	std::cout << node->getName() << node->referenceCount() << std::endl;
	osg::ref_ptr root = new	osg::Group;
	root->addChild(node);
	std::cout << node->getName() << node->referenceCount() << std::endl;
	return 0;
}
运行代码,出错,控制台输出:
glider0
glider1
0
解释:创建完成node之后,由于并未定义成只能指针,计数为0(其实这个计数是没有任何意义的,马上解释),在第一个片段中,加入根节点之后,计数加1,当第一个片段结束时,根节点被析构,导致node被析构,所以计数在此为0,(虽然两次计数都是0,但本质上已经不同了,第二次输出0的时候node的内存已经不属于node,所以刚才说那个计数0没有任何意义),通过调试可以发现,第三次输出实际上已经产生错误,没能计算出名字
解决方法:将node定义成智能指针,即:
osg::ref_ptr node = osgDB::readNodeFile("glider.osg");
运行代码,通过,输出:
glider1------>初始化计数1
glider2------>加入父节点,计数+1
glider1------>第一个片段结束时,父节点被析构,计数-1
glider4------>两次加入父节点,计数+2
glider3------>被移除一次,计数-1
glider1------>父节点root2,root3被析构,计数-2
glider3------>计数+2
glider3------>不是1!!!那么新的问题来了。
glider4

解释,对比片段2和片段3可以发现,他们最大的区别在于父节点是智能指针对象还是普通指针,片段3将内存分配到堆上,必须手动释放才行;而片段2定义的智能指针对象为普通对象,分配到栈上,模块结束时自动析构,他的析构会导致他的子节点计数减少1,即,node计数减少。解决方法:由于~Group为 protected类型,不能手动调用,这里先把他加入到根节点下然后remove释放掉。
 osg::Group* rroot = new osg::Group;
 {
  osg::Group* root = new osg::Group;
  root->addChild(node);
  //root->addChild(node);
  osg::Group* root2 = new osg::Group;
  root2->setName("root2");
  root2->addChild(node);
  std::cout << node->getName() << node->referenceCount() << std::endl;
  //error ~Group() Protected Member Functions
  //delete root;
  rroot->addChild(root);
  rroot->addChild(root2);
 }
 rroot->removeChild(0, rroot->getNumChildren());
现在再输出应该没问题了吧。

未完。


























































































































































你可能感兴趣的:(OSG)