VTK中vtkSmartPointer使用疑问:局部过滤器未致程序崩溃原因
VTK智能指针与管线对象存活机制解析
你观察得非常仔细,这个问题的核心确实是VTK的引用计数机制在管线连接中的作用,我来一步步给你拆解清楚:
为什么applyFilters里的过滤器没有被销毁?
当你在VTK中使用SetInputConnection(或者SetCutFunction这类设置依赖对象的方法)时,下游对象会自动增加上游对象的引用计数:
- 当你调用
cutter->SetInputConnection(clip->GetOutputPort()),cutter会持有clip的一个引用,让clip的引用计数+1; - 同理,
clip通过SetInputConnection(c2p->GetOutputPort())持有c2p的引用; - 而
plane被cutter->SetCutFunction(plane)设置后,cutter也会持有plane的引用。
当applyFilters函数返回cutter时,main函数里的vtkSmartPointer<vtkPolyDataAlgorithm> poly_algo会接管这个对象,让cutter的引用计数保持在至少1的状态。既然cutter存活,它持有的所有上游对象(clip、c2p、plane)的引用计数都大于0,自然不会被销毁。
直到程序结束时,poly_algo超出作用域,cutter的引用计数降到0,被智能指针自动销毁。这时候它会释放对clip的引用,clip的计数也降到0,随之销毁,进而释放c2p,以此类推,整个管线的所有对象都会被正确清理——这就是为什么vtkDebugLeaks没有检测到泄漏的原因。
关于类中实现VTK管线的疑问
你的猜想是对的,在类中实现VTK管线时,确实不需要保存所有创建的VTK对象,只需要保留管线的"关键节点"即可:
- 通常这个关键节点是管线的末端对象(比如最终的算法输出、mapper或者actor),只要这个对象被你的类持有(比如用
vtkSmartPointer作为成员变量),整个管线的上游对象都会因为连接的引用计数而保持存活。 - 完全不需要手动调用
->Delete(),vtkSmartPointer会自动管理引用计数,当所有引用都消失时,对象会被自动销毁。 - 唯一需要注意的是:如果某个对象没有被管线中的任何其他对象引用(比如你创建了一个临时算法但没把它加入管线连接),那它会在对应的
vtkSmartPointer超出作用域时被销毁——但只要是正常接入管线的对象,都不需要额外保存。
举个例子,如果你的类里只保存vtkSmartPointer<vtkActor>作为成员,那么actor持有mapper,mapper持有上游算法,整个链上的所有过滤器、数据源都会被间接持有,直到actor被销毁时才会依次释放。
你的测试代码
pointertest.cxx
#include <vtkPolyData.h> #include <vtkSmartPointer.h> #include <vtkPolyDataMapper.h> #include <vtkActor.h> #include <vtkRenderWindow.h> #include <vtkRenderer.h> #include <vtkRenderWindowInteractor.h> #include <vtkStructuredGrid.h> #include <vtkPoints.h> #include <vtkCellCenters.h> #include <vtkDoubleArray.h> #include <vtkCellDataToPointData.h> #include <vtkCellData.h> #include <vtkClipDataSet.h> #include <vtkPlane.h> #include <vtkCutter.h> #include <vtkPolyDataAlgorithm.h> vtkSmartPointer<vtkPolyDataAlgorithm> applyFilters(vtkSmartPointer<vtkStructuredGrid> grid) { // Convert cell data to point data vtkSmartPointer<vtkCellDataToPointData> c2p = vtkSmartPointer<vtkCellDataToPointData>::New(); c2p->PassCellDataOn(); c2p->SetInputData(grid); // Clip at value r = 4.5 vtkSmartPointer<vtkClipDataSet> clip = vtkSmartPointer<vtkClipDataSet>::New(); clip->SetInputConnection(c2p->GetOutputPort()); clip->SetInputArrayToProcess(0, 0, 0, 0, "R"); clip->SetValue(4.5); clip->InsideOutOn(); // Make plane vtkSmartPointer<vtkPlane> plane = vtkSmartPointer<vtkPlane>::New(); plane->SetOrigin(0.,0.,0.); plane->SetNormal(0, 0, 1); // Cut vtkSmartPointer<vtkCutter> cutter = vtkSmartPointer<vtkCutter>::New(); cutter->SetCutFunction(plane); cutter->SetInputConnection(clip->GetOutputPort()); return cutter; } int main() { // Create structured grid int nx = 101, ny = 101, nz = 101; double dx, dy, dz; dx = dy = dz = 10./(nx-1); vtkSmartPointer<vtkStructuredGrid> grid = vtkSmartPointer<vtkStructuredGrid>::New(); grid->SetDimensions(nx, ny, nz); vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New(); for (int i = 0; i < nx; ++i) { for (int j = 0; j < ny; ++j) { for (int k = 0; k < nz; ++k) { pts->InsertNextPoint(-5+dx*i, -5+dy*j, -5+dz*k); } } } grid->SetPoints(pts); // Create cell scalar field vtkSmartPointer<vtkDoubleArray> arr = vtkSmartPointer<vtkDoubleArray>::New(); arr->SetNumberOfComponents(1); arr->SetName("R"); vtkSmartPointer<vtkCellCenters> cell_centres = vtkSmartPointer<vtkCellCenters>::New(); cell_centres->SetInputData(grid); cell_centres->Update(); for (int i = 0; i < grid->GetNumberOfCells(); ++i) { double pt[3]; cell_centres->GetOutput()->GetPoint(i, pt); double r = pt[0]*pt[0] + pt[1]*pt[1] + pt[2]*pt[2]; arr->InsertNextValue(r); } grid->GetCellData()->AddArray(arr); // Call clipping functions vtkSmartPointer<vtkPolyDataAlgorithm> poly_algo = applyFilters(grid); // Create a mapper and actor vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); mapper->SetInputConnection(poly_algo->GetOutputPort()); vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New(); actor->SetMapper(mapper); // Create a renderer, render window and interactor vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New(); vtkSmartPointer<vtkRenderWindow> render_window = vtkSmartPointer<vtkRenderWindow>::New(); render_window->SetWindowName("Plane"); render_window->AddRenderer(renderer); vtkSmartPointer<vtkRenderWindowInteractor> window_interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); window_interactor->SetRenderWindow(render_window); // Add the actors to the scene renderer->AddActor(actor); // Render and interact render_window->Render(); window_interactor->Start(); return EXIT_SUCCESS; }
编译用CMakeLists.txt
cmake_minimum_required(VERSION 3.10) project(PointerTest) find_package(VTK REQUIRED) include(${VTK_USE_FILE}) add_executable(pointertest pointertest.cxx) target_link_libraries(pointertest ${VTK_LIBRARIES})
内容的提问来源于stack exchange,提问作者Francois
相关产品推荐
相关产品推荐

