VTK修炼之道80:VTK开发基础_智能指针与引用计数
1.引用計數
VTK經過多年的開發與維護,已經形成了一套穩定的框架和開發規則。因此,了解這些規則和框架是定制VTK類的基礎,這其中用到了大量面向對象的設計模式,例如對象工程模式、觀察者/命令模式;還有就是當下非常流行的引用計數與智能指針等高級內存管理等。
內存管理在大型的工程中是非常重要的內容,如果不能有效地管理內存,將嚴重影響到應用程序的執行效率,甚至可能造成程序崩潰。之前學習C++基礎時,教材中都會反復的強調,使用new操作符申請的空間,一定要使用delete來釋放。C++中并沒有提供高級的內存管理與垃圾回收機制,通常進行手動管理。這對于簡單的程序而言可以輕松完成,但是對于大型程序就會疲于應付。最有代表性例子就是,當一個內存塊(可以看做一個指針)被多個對象引用時,刪除任意一個對象,都可能影響其他對象,引用計數和智能指針剛好用來解決這個問題。
1.1 引用計數
簡單來說,引用計數就是每個對象中維護一個引用計數的變量,表示當前對象被多少對象引用。
當一個對象被另一個對象引用時,該對象的引用計數就會加1;當一個對象取消對該對象的引用時,該對象的引用計數減1.當引用計數為0時,程序就會撤銷該對象。
VTK中實現引用計數的類為vtkObjectBase。VTK是一個C++類庫,在VTK中,C++的繼承與多態得到了完美的體現。經過十幾年的發展,所有的VTK類集合可以看做一個樹狀結構,vtkObjectBase則是他們共同的祖先。
這也說明了絕大部分VTK類都支持引用計數。vtkObjectBase中定義了一個ReferenceCount變量,改變量記錄了引用計數。當一個vtkObjectBase及其子類對象創建時,ReferenceCount就會被初始化為1。
vtkObjectBase::vtkObjectBase {this->ReferenceCount = 1; }在該類中,vtkObjectBase的構造函數、析構函數、拷貝構造函數以及“=”操作符都被聲明為“protected”類型,因此不能顯示地構造和銷毀vtkObjectBase及其子類對象。vtkObjectBase定義了一個靜態函數New(),用于生成vtkObjectBase對象。New()函數中調用了構造函數來生成一個對象,并在構造函數中初始化引用計數為1.1.2?Register()函數以及Unregister()函數實現計數
生成一個vtkObjectBase及其子類對象后,該對象并不會孤立地存在,多數情況下又可能被其他對象引用。這是需要調用Regester()函數實現引用計數加1;Register()函數中有一個vtkObjectBase*類型的形參,代表引用當前對象的其他對象的類型(可以設置為NULL)。因此,引用計數關心的是被引用的數量,而不關心引用者是誰。而Unregister()函數實現引用計數減1,并檢查引用計數的數量。當引用計數為零時,自動銷毀該對象。
1.3?Delete()函數刪除對象釋放內存
對于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中。
vtkRenderer::SetActiveCamera()函數的代碼如下:
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); }解釋:
vtkRenderer中定義了一個vtkCamera對象ActiveCamera。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()后,其引用計數減一,此時camera計數為零,刪除camera對象。
1.4 引用計數的先天缺陷
其實,引用計數并不是十分的完美。本身就有先天的缺陷——對循環引用無能為力。即無法處理對象之間相互引用形成一個環路的情況,例如,VTK中vtkAlgrthm和vtkExecute對象之間。2.智能指針
智能指針可以完全避免內存泄漏問題。
2.1 智能指針
VTK中智能指針類為vtkSmartPointer。VTKSmartPointer是一個模板類,繼承自VTKSmartPointerBase類。VTKSmartPointerBase中定義了一個vtkObjectBase類型的指針對象Object,用于存儲智能指針中實際生成的對象。智能指針定義為:
vtkSmartPoint<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New(); //引用計數為1VTKSmartPointer中定義了靜態函數New()來生成一個智能指針對象。
該函數的核心在于:會根據模板參數類型來生成一個對象,并將其保存在基類VTKSmartPointerBase的成員變量Object中。
- VTKSmartPointer中重載了“->”操作符
- VTKSmartPointer重載了“=”操作符
例如:
vktSmartPointer<vtkCamera> camera1 =vtkSmartPointer<vtkCamera>::New(); vtkSmartPointer<vtkCamera> camera2 = camera1;需要注意的是,此時camera1和camera2的引用計數都等于2。
過程為:首先camera1的vtkCamera對象Object調用Register()函數,自動將引用計數加1,談后將camera2的Object指向camera1的Object對象。
2.2 智能指針釋放內存
當一個智能指針對象的生命周期結束時,會自動調用其析構函數釋放內存。在析構函數中會調用其內部對象Object的UnRegister()函數修改引用計數。如果此時的引用計數為0,Object對象會自動釋放內存。
3. vtkObjectBase中的幾個重要函數
3.1 GetClassName()
該函數用于返回當前類的名字。其通過調用類內保護類型的虛函數GetClassNameInternal()來實現。vtkObjectBase時VTK中絕大對數類的基類,因此這些類都可以訪問GetClassName()函數來獲取類名。我們必須在這子類中覆蓋GetClassNameInternal()函數,這樣才會有“多態性”效應。
3.2 IsTypeOf/IsA()
IsTypeOf()是一個靜態函數,其參數為一個char類型字符串,通常為一個類的名字,用于判斷一個類名是否為vtkObjectBase。
虛函數IsA()則調用IsTypeOf()來判斷一個對象的類型。vtkObjectBase的類中都覆蓋了IsA(),以便判斷實際的類型。
3.3 Print()/PrintSelf()/PrintHeader()/PrintTrailer()
Print()用于輸出類的成員變量和狀態,其內部調用PrintSelf()/PrintHeader()/PrintTrailer()三個虛函數。
4. 常用vtkObjectBase子類及其繼承關系
- vtkCommand主要涉及觀察者/命令模式的實現。
- vtkInformationKey與vtkInformation搭配使用,用于實現VTK的執行管線。
- vtkObject是一個非常非常重要的基類!!其子類包括vtkAlgrithm和vtkExecutive兩個實現Filter類最重要的類;而vtkDataObject是VTK中所有數據結構類如:vtkPolyData、vtkImageData等的基類。
5.參看資料
1.《C++ primer》
2.《The VTK User’s Guide – 11thEdition》
3. ?張曉東, 羅火靈. VTK圖形圖像開發進階[M]. 機械工業出版社, 2015.
總結
以上是生活随笔為你收集整理的VTK修炼之道80:VTK开发基础_智能指针与引用计数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VTK修炼之道79:交互与拾取_单位拾取
- 下一篇: 企业巧妙运用飞秋提高工作效率