先看下这个代码,有什么问题:
#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);
}
所以在最后得到的这个指针是个无效的指针。
正确的方法应该是:
#include <osg/Group>
#include <osg/Node>
#include <osg/Geode>
#include <iostream>
#include <cstdio>
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::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);
}
}
}
int main()
{
createNode();
osg::ref_ptr<osg::Node> node = NULL;
GetNodeFromRoot(node);
std::string name = node->getName();
std::cout<<name<<std::endl;
getchar();
}
还有一种情况容易出问题:
#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();
}
这种情况可能也忽悠人
int main()
{
osg::ref_ptr<osg::Group>root = new osg::Group;
osg::ref_ptr<osg::Geode>geode = new osg::Geode;
root->addChild(geode);
{
osg::ref_ptr<osg::Group>tmp = new osg::Group;
tmp->addChild(geode );
}
int num = geode->referenceCount();//Num应该为2
int fff = geode->getNumParents();//fff为1
{
osg::Group * tmp =new osg::Group;
tmp->addChild(geode);
}
fff = geode->getNumParents();//fff为2
num = geode->referenceCount();//Num应该为3
}
最后一个和标准STL容器结合使用,这个情况使用的应该很多,但出现问题的概率也比较大
#include <osg/Group>
#include <osg/Node>
#include <osg/Geode>
#include <osg/MatrixTransform>
#include <stack>
int main()
{
osg::Group * tmp = new osg::Group;
//test1
{
std::stack<osg::MatrixTransform *> mStack1;
{
osg::ref_ptr<osg::MatrixTransform> m = new osg::MatrixTransform;
mStack1.push(m);
int i = m->referenceCount();
}
osg::MatrixTransform * m = mStack1.top();
// m->addChild(tmp);//此处是有问题的,因为此时的m已经不是一个有效的指针了。
// int i = m->referenceCount();
}
//Test2 正确情况
{
std::stack<osg::ref_ptr<osg::MatrixTransform> >mStack2;
{
osg::ref_ptr<osg::MatrixTransform> m = new osg::MatrixTransform;
mStack2.push(m);
int i = m->referenceCount();
}
osg::MatrixTransform * m = mStack2.top();
m->addChild(tmp);
int i = m->referenceCount();
}
return 0;
}
总结:
1. 在osg::ref_ptr<osg::Node>node = new osg::Node; 其中node 为osg::ref_ptr的对象,而不是指针。
2. OSG 中新创建的场景对象建议使用ref_ptr 进行内存分配和管理
3. 对于不使用ref_ptr 的对象,引用计数值变得没有意义,并且它无法自动从场景中卸载。
4. 新建对象作为函数结果返回时,应该返回release()。并尽快引入到别的场景中,否则发生内存泄露
5. 只有osg::ref_ptr 类 来管理 osg对象的引用计数,其他脱离了(和osg::ref_ptr对象无关的操作)osg::ref_ptr 管理的操作如:赋值等将不会对引用计数产生影响