VTK:智能指针与引用计数

1.引用计数

内存管理在大型的工程中是非常重要的内容,如果不能有效的管理内存,将严重影响到应用程序的执行效率,甚至可能造成程序崩溃。在之前学过的C++中,使用new操作符申请的空间,用delete来释放。C++中并没有提高的内存管理与回收机制,通常进行手动管理。这对于简单的程序而言可以轻松完成,但是对于大型程序就不能应对。例如当一块内存块被多个对象引用时,删除任意一个对象,都可能影响其他对象,引用计数和智能指针刚好可以解决这个问题。
引用计数:
简单来说,引用计数就是每个对象中维护一个引用计数的变量,表示当前对象背多少对象引用。
当一个对象被另一个对象引用时,该对象的引用计数就会加1;当一个对象取消该对象的引用时,该对象的引用次数减一。当引用计数为0时,程序就会撤销该对象。
VTK中实现引用计数的类vtkObjectBase。VTK是一个C++类库,在VTK中,C++的继承与多态得到了完美的体现。所有的VTK集合可以看做一个树形结构,vtkObjectBase则是他们共同的祖先。这也说明了绝大部分VTK都支持计数。vtkObjectBase中定义了一个ReferenceCount变量,改变量记录引用计数。当一个vtkObjectBase及其子类对象创建时,ReferenceCount被初始化为1.vtkObjectBase::vtkObjectBase { this->ReferenceCount = 1; }
在该类中,vtkObjectBase的构造函数、析构函数、拷贝函数以及“=”操作符都被声明为“protected”类型,因此不能显示地构造和销毁vtkObjectBase及其子类对象。New()函数中调用了构造函数来生产一个对象,并构造函数中初始化引用计数1.

1.2Register()函数以及Unregister()函数实现计数

生成一个vtkObjectBase及其子类对象后,该对象并不会孤立地存在,多数情况下又可能被其他对象引用。这需要调用Register()函数实现引用计数加1;Register()函数中有一个vtkObjectBase*类型的参数,代表引用当前的其他对象的类型(可以设置为NULL)。因此,引用计数关心的被引用的数量,而不关心引用者是谁。而Unregister()函数实现计数减1,并检查引用计数的数量。当引用计数为零时,自动撤销该对象。

1.3Delete()函数删除对象释放内存

对于New()的对象,一定要通过Delete()对象来删除。Delete()函数并非直接删除对象,而调用UNregister()对象将引用计数减1,如果引用计数为0,则调用析构函数来删除对象。
一个简单的实例如下:
vtkCamera* camera = vtkCamera::New(); //引用计数为1 renderer->SetActiveCamera(camera); //引用计数为2 renderer->Delete(); //引用计数是1 camera->Delete(); //camera被删除首先调用vtkCamera::New()
函数实例化一个vtkCamera对象camera。,此时camera的引用计数初始化为1.然后将camera通过SetActiveCamera()函数传递至一个vtkRenderer对象renderer中。

void vtkRenderer::SetActiveCamera(vtkCamera*  cam)
{
      if(this->ActiveCamera == cam)
        {
            return;
        }
      if(this->ActiveCamera)
        {
           this->ActiveCamera->UnRegister(this);
           this->ActiveCamera = NULL;
        }
      if( cam )
        {
           cam->Register( this );
        }
      this-<ActiveCamera == cam;
      this->Modified();
      this->InvokeEvent(vtkCommand::ActiveCameraEvent, cam);
}

vtkRederer中定义了一个vtkCamera对象ActiveCanmera.SetActiveCamera()函数用于设置该对象的值。在调用SetActiveCamera()函数时,如果当前已经设置了ActiveCamera,则先Unregister()该对象,并将其指向NULL。然后,调用Register()函数增加一个引用,说明camera在renderer中该应用,并将ActiveCamera指向camera。此时,camera的引用计数数目为2(如果这里又有一个新的vtkCamera对象通过SetActiveCamera设置,同样先将此前设置的camera对象的引用计数减1,再赋值)。而执行renderer->Delete()函数时,由于renderer的引用计数为1,所以renderer会被销毁,而此时camera又变为1.当执行camera->Delete()后,其引用计数减1,此时camera计数为零,删除camera对象。

1.4引用计数的先天缺陷

其实,引用计数并不是十分完美。本身就有先天的缺陷——对循环引用无能为力。即无法处理对象之间相互引用成一个环路的情况,例如,VTK中vtlAlgrthm和vtkExecute对象之间。

2智能指针

智能指针可以完全避免内存泄露问题

2.1智能指针

VTK中智能指针类为vtkSmartPointer。VTKSmartPointer是一个模板类,继承自VTKSmartPointerBase类。VTKSmartPointerBase中定义了一个vtkObjectbase类型的指针对象Object,用于存储智能指针中实际生成的对象。智能指针定义为:vtkSmartPoint<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New(); //引用计数为1
vtkSmartPointer中定义了静态函数New()来生产一个智能指针对象。该函数的核心在于:会根据模板参数类型来生产一个对象,并将其保存在基类VTKSmartPointerBase的成员变量Object中。
VTKSmartPointer中重载了“->”操作符
返回实际模板参数类型对象,因此可以方便地访问对象的成员函数,如camera->setFocusPostion(0,0,0).
VTKSmartPointer重载了“=”操作符
可以在VTKSmartPointer对象之间进行赋值。在赋值过程中,VTKSmartPointer会自动控制其内部对象指针的引用计数加1.
例子:vktSmartPointer<vtkCamera> camera1 = vtkSmartPointer<vtkCamera>::New(); vtkSmartPointer<vtkCamera> camera2 = camera1;
此时的camera1和camera2的引用计数都等于2.过程为: 首先camera1和vtkCamera对象调用Register()函数,自动将引用计数加1,谈后将camera2的Object对象。
2.2智能指针释放内存
当一个智能指针对象的生命周期结束时,会自动调用其析构函数释放内存。在析构函数中会调用其内部对象Object的UnRegister()函数修改引用计数。如果此时的计数为零,Object对象会自动释放内存。

3.vtkObjectBase中的几个重要函数

  1. GetClassName()

该函数用于返回当前类的名字。其通过调用类内保存类型的虚函数GetClassNameInternal()来实现。vtkObjectBase时VTK中绝大多数的基类,因此这些类都可以访问GetClassName()函数,这样才会有“多态性”效应。

  1. IsTypeOf/IsA()

IsTypeOf()是一个静态函数,其参数为一个char类型字符串,通常为一个类的名字,用于判断一个类名是否为vtkObjectBase。
虚函数IsA()则调用IsTypeOf()来判断一个对象的类型。vtkObjectBase的类中都覆盖了IsA(),以便判断实际的类型。

  1. Print()/PrintSelf()/PrintHeader()/PrintTrailer()
    Print()y用于输出类的成员变量和状态,其内部调用PrintSelf()/PrintHeader()/PrintTrailer()三个虚函数。

4.常用的vtkObjectBase子类及其继承关系

在这里插入图片描述

  • vtkCommand主要涉及观察者/命令模式的实现。
  • vtkInformationKey与vtkInformation搭配使用,用于实现VTK的执行管线。
  • vtkObject是一个非常非常重要的基类!!其子类包括vtkAlgrithm和vtkExecutive两个实现Filter类最重要的类;而vtkDataObject是VTK中所有数据结构类如:vtkPolyData、vtkImageData等的基类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

简 。单

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值