VTK智能指针

文章目录

    • 一、VTK中的New函数
    • 二、引用计数
    • 三、VTK中的智能指针
    • 四、运行时类型识别

一、VTK中的New函数

在 VTK(Visualization Toolkit)中,New() 函数是创建 VTK 对象的主要方式。它是每个 VTK 类的一个静态方法,专门用于分配和初始化对象,并且与 VTK 的内存管理机制密切相关。

1.New函数的作用

  • 动态分配内存:New() 使用堆内存分配来创建对象(类似于 C++ 中的 new 操作符)。
  • 初始化引用计数:在调用 New() 时,分配的对象会将其引用计数初始化为 1,便于与 VTK 的智能指针(如 vtkSmartPointer)配合使用。
  • 保证对象实例化:所有 VTK 对象的实例化都通过其工厂机制实现,确保对象的创建符合 VTK 的设计要求。

2.使用 New创建对象
以下是使用 New() 的常见步骤和示例:

#include <vtkSphereSource.h>int main() {// 使用 New() 创建 vtkSphereSource 对象vtkSphereSource* sphere = vtkSphereSource::New();// 设置一些属性sphere->SetRadius(5.0);sphere->SetPhiResolution(20);sphere->SetThetaResolution(20);// 调用 Update() 方法生成几何体sphere->Update();// 使用完对象后,需要手动释放内存sphere->Delete();return 0;
}

3.New与内存管理

  • 使用 New() 创建的对象默认引用计数为 1。
  • 在对象使用完毕后,必须调用 Delete() 手动释放内存。
  • 如果未调用 Delete(),将会导致内存泄漏。
vtkClass* obj = vtkClass::New();
// 使用对象
obj->DoSomething();
// 手动释放内存
obj->Delete();

与智能指针结合:
建议结合 vtkSmartPointer 使用 New(),让智能指针自动管理内存,避免手动调用 Delete()。

vtkSmartPointer<vtkClass> obj = vtkSmartPointer<vtkClass>::New();
obj->DoSomething();

4.与工厂机制的关系
VTK 的对象创建通常由其内部的工厂机制处理。New() 是类工厂的一部分,用于抽象具体的实例化逻辑。如果启用了对象的派生工厂机制,New() 会返回派生类的实例,而不是基类。

#include <vtkObjectFactory.h>
#include <vtkSphereSource.h>// 自定义类继承自 vtkSphereSource
class CustomSphereSource : public vtkSphereSource {
public:static CustomSphereSource* New();vtkTypeMacro(CustomSphereSource, vtkSphereSource);void PrintSelf(ostream& os, vtkIndent indent) override {this->Superclass::PrintSelf(os, indent);os << "CustomSphereSource Object" << std::endl;}
};// 注册自定义类到工厂
vtkStandardNewMacro(CustomSphereSource);// 使用工厂机制
int main() {vtkSphereSource* sphere = vtkSphereSource::New();sphere->PrintSelf(std::cout, vtkIndent());sphere->Delete();  // 手动删除return 0;
}

二、引用计数

如果很多对象有相同的值,在程序里没有必要将这个值存储多次。更好的办法是让所有的对象共享这个值。这么做不但节省内存,而且可以使程序运行的更快,因为不需要构造和析构这个值的副本。引用计数就是这样一个技巧,它允许多个相同值的对象共享某个值。引用计数是个简单的垃圾回收体系,只要其他对象引用某对象(记为对象O),对象O就会增加一个引用计数,当最后引用对象O的对象移除,O对象就会自动析构,VTK里使用引用计数的好处是,可以实现数据之间的共享而不是复制,从而达到节省内存的目的。

#include <QDebug>
#include <vtkBMPReader.h>
#include <vtkSmartPointer.h>
#include <vtkImageData.h>int main(int argc, char *argv[])
{QApplication a(argc, argv);vtkSmartPointer<vtkBMPReader> reader = vtkSmartPointer<vtkBMPReader>::New();reader->SetFileName("./vtk-logo.bmp");reader->Update();qDebug() << "Reference_0:" << reader->GetOutput()->GetReferenceCount();vtkSmartPointer<vtkImageData> image1 = reader->GetOutput();qDebug() << "Reference_1:" << reader->GetOutput()->GetReferenceCount();qDebug() << "image1:" << image1->GetReferenceCount();vtkSmartPointer<vtkImageData> image2 = reader->GetOutput();qDebug() << "Reference_2:" << reader->GetOutput()->GetReferenceCount();qDebug() << "image2:" << image1->GetReferenceCount();return a.exec();
}

输出结果如下所示:
在这里插入图片描述
上述示例先使用vtkBMPReader读入一幅BMP图像,在赋值之前输出了reader->GetOutput()的引用计数值,其值为1(使用方法New()创建对象以后,初始的引用计数值就等于1);然后创建了一个vtkImageData类型的对象image1,并把reader的输出赋给了image1,这时image1就指向了reader的输出,即reader的输出多了一个引用,这时输出的reader->GetOutput()和image1的引用计数都为2;接着又创建一个类型同样为vtkImageData的对象image2,同样把reader的输出赋值给了image2,这时image2也指向reader的输出,即reader的输出又多了一个引用计数,所以输出的reader->GetOutput()和image2的引用计数值变成了3。一旦某个对象的引用计数等于0,就表明没有别的对象再引用它,它的使命也就宣告完成了,程序就会自动析构这个对象,在上述示例中看不到引用计数减少的原因是使用了智能指针vtkSmartPointer,只要程序不结束,引用计数就不会减少。

三、VTK中的智能指针

智能指针会自动管理引用计数的增加与减少,若检测到某对象的引用计数减少为0,则会自动释放该对象的资源,从而达到自动管理内存的目的。上述内容已经介绍过,在VTK中创建一个对象可以用两种方法,一种是使用vtkObjectBase里的静态成员变量New(),用Delete()方法析构;另一种就是示例中使用多次的智能指针vtkSmartPointer。
对于第一种方法,用 New()创建的对象,程序最后必须调用 Delete()方法使引用计数减1,而且由于 vtkObjectBase 及其子类的构造函数都是声明为受保护的,这意味着它们不能在栈区(栈和堆的区别:栈区上的内存是由编译器自动分配与释放的,堆区上的内存则是由程序员分配和手动释放的。)上分配内存,比如:

vtkBMPReader* reader = vkBMPReader:New(); //创建 VtkBMPReader 对象
......
reader->delete(); // 程序最后要调用Delete(),这里并没有直接析构对象,而是使引用计数减1

使用New()创建的对象,如果没有用Delete()方法删除,程序有可能会出现内存泄漏,即用户负责对象内存的管理。若使用智能指针创建对象,则无需手动调用 Delete()方法减少引用计数,因为引用计数的增加与减少都是由智能指针自动完成的。使用智能指针时,首先要包含智能指针的头文件vtkSmartPointer.h。vtkSmartPointer 是一个模板类,所需的模板参数就是待创建的对象的类名,例如:

vtkSmartPointer<vtkImageData> image = vtkSmartPointer<vtkImageData>::New();

注意上面的一行代码等号右边写法,不能写为:

vtkSmartPointer<vtkImageData> image = vtkImageData::New();

也就是说,不能把对象的原始指针赋给智能指针,上述代码编译时可以通过,但程序退出时会有内存泄漏的问题。

如果没有给对象分配内存,仍然可以使用智能指针,比如

vtkSmartPointer<vtkBMPReader> reader = vtkSmartPointer<vtkBMPReader>::New();
vtkImageData* imageData = reader->GetOutput();

或者写为:

vtkSmartPointer<vtkImageData> imageData = reader->GetOutput();

第一种情况,当reader超出其作用域时,数据即会被删除;第二种情况,使用了智能指针,所以数据的引用计数会自动加1,除非reader和imageData都超出它们的作用域,数据才会被删除。

四、运行时类型识别

在C++里,对象类型是通过 typeid(需要包含头文件#include <type_info>)获取的:VTK里在 vtkObjectBase 定义了获取对象类型的方法—GetClassName()和 IsA()。GetClassName()返回的是该对象类名的字符串(VTK 用类名来识别各个对象),如:

vtkSmartPointer<vkBMPReader> reader =  vikSmartPoinler<vkBMPReader>:New()const char* bype = reader->GeiClassName();/返回“vkKBMPReader”字符串

ISA()方法用于测试某个对象是否为指定字符串的类型或其子类类型,比如:

if (reader->IsA("vtkImageReader")) { ...... }; //这里IsA()会返回真

类比 C++里的操作 RTTI(Real-time tpe inforpation)操作符,除了typeid 之外,还有dynamic_cast,主要用于基类向子类的类型转换,称为向下转型。VTK 里同样提供了类似的方法,也就是 vtkObject 里定义的 SafeDownCast(),它是 vtkObject 里的静态成员函数,意味着它是属于类,而不是属于对象的,即可以用 vtkObject:SafeDownCast0直接调用,比如:

vtkSmartPointer<vtkImageReader> readerBase = vtkSmartPointer<vtkImageReader>::New();
vtkBMPReader* bmpReader = vtkBMPReader::SafeDownCast(readerBase);

与 dynamic_cast 类似,SafeDownCast 也是运行时才转换的,这种转换只有当 bmpReader确实是readerBase的派生类时才生效,否则返回空指针。除了运行时类型识别,vtkObjectBase 还提供了用于调试的状态输出接口 Prin(),其调用内部 PrintSelf()、PrintHeader()、PrintTrailer()等函数实现。在调试 VTK 程序时,如果需要输出某个对象的状态信息时,一般都是调用 Print()函数,如:

bmpReader->Print(std::cout);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/64453.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ai绘图丨中国新年春节背景第一弹(附关键词

一、引言 随着春节的临近&#xff0c;节日的氛围愈发浓厚。在电商、社交媒体宣传或者个人创作等诸多场景中&#xff0c;一张精美的中国新年春节背景图都能为作品增色不少。如今&#xff0c;借助 AI 绘图技术&#xff0c;我们能够轻松地创作出独具特色的春节背景图。本文将以 “…

计算机学习

不要只盯着计算机语言学习&#xff0c;你现在已经学习了C语言和Java&#xff0c;暑假又规划学习Python&#xff0c;最后你掌握的就是计算机语言包而已。 2. 建议你找一门想要深挖的语言&#xff0c;沿着这个方向继续往后学习知识就行。计算机语言是学不完的&#xff0c;而未来就…

鸿蒙项目云捐助第七讲鸿蒙App应用的首页推荐模块布局的实现

鸿蒙项目云捐助第七讲鸿蒙App应用的首页推荐模块布局的实现 最后设置首页的推荐模块&#xff0c;参考模板如下图所示。 一、首页热门推荐模块的实现 对于热门推荐模块&#xff0c;先有上面的小标题栏&#xff0c;这里的标题栏也有一个小图标&#xff0c;首先从“百度图库”中…

电子应用设计方案-58:智能沙发系统方案设计

智能沙发系统方案设计 一、引言 智能沙发作为一种融合了舒适与科技的家居产品&#xff0c;旨在为用户提供更加便捷、舒适和个性化的体验。本方案将详细介绍智能沙发系统的设计思路和功能实现。 二、系统概述 1. 系统目标 - 实现多种舒适的姿势调节&#xff0c;满足不同用户的…

【vue-codemirror】Vue中强大的编辑器插件--vue-codemirror

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

Linux下学【MySQL】所有常用类型详解( 配实操图 通俗易懂 )

每日激励&#xff1a;“当你觉得你会幸运时&#xff0c;幸运就会眷顾你&#xff0c;所以努力吧&#xff0c;只要你把事情做好&#xff0c;并觉得你会幸运&#xff0c;你将会变得幸运且充实。” 绪论​&#xff1a; 本章继续学习MySQL的知识&#xff0c;本章主要讲到mysql中的所…

你了解网络层的 ICMP 吗?

你了解网络层的 ICMP 吗&#xff1f; 一. 什么是 ICMP二. ICMP 的工作原理三. ICMP 的结构四. ICMP 的常见应用五. ICMP 的局限性与安全性六. 总结 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神…

uniapp使用百度地图配置了key,但是显示Map key not configured

搞了我两天的一个问题。 hbuilderx版本&#xff1a;4.36 问题介绍&#xff1a; 我的项目是公司的项目&#xff0c;需要在H5端使用百度地图&#xff0c;使用vue-cli创建的uniapp&#xff0c;就是uni代码在src里的目录结构。就是使用这种方式才会遇到这个问题。 问题原因&#xf…

【Qt】drawText字体大小问题探究

背景 软件的一个功能是&#xff1a; 打开图片在图片上绘制序号&#xff0c;序号的样式是圆圈内包含数字将带有序号的图片打印出来 实现思路也很简单&#xff0c;在屏幕上显示时重写paintEvent函数&#xff0c;利用QPainter完成图片和序号的绘制。打印时只需要将QPainter对应…

Win11安装安卓子系统WSA

文章目录 简介一、启用Hyper-V二、安装WSA三、安装APKAPK商店参考文献 简介 WSA&#xff1a;Windows Subsystem For Android 一、启用Hyper-V 控制面板 → 程序和功能 → 启用或关闭 Windows 功能 → 勾选 Hyper-V 二、安装WSA 进入 Microsoft Store&#xff0c;下拉框改为 …

数据结构 ——二叉树转广义表

数据结构 ——二叉树转广义表 1、树转广义表 如下一棵树&#xff0c;转换为广义表 root(c(a()(b()()))(e(d()())(f()(j(h()())())))) (根&#xff08;左子树&#xff09;&#xff08;右子树&#xff09;) 代码实现 #include<stdio.h> #include<stdlib.h>//保存…

企业车辆管理系统(源码+数据库+报告)

一、项目介绍 352.基于SpringBoot的企业车辆管理系统&#xff0c;系统包含两种角色&#xff1a;管理员、用户,系统分为前台和后台两大模块 二、项目技术 编程语言&#xff1a;Java 数据库&#xff1a;MySQL 项目管理工具&#xff1a;Maven 前端技术&#xff1a;Vue 后端技术&a…

ubuntu20.04复现 Leg-KILO

这里写目录标题 opencv版本问题下载3.2.0源代码进入解压后的目录创建构建目录运行 CMake 配置 配置时指定一个独立的安装目录&#xff0c;例如 /opt/opencv-3.2&#xff1a;出错&#xff1a; 使用多线程编译错误1&#xff1a; stdlib.h: 没有那个文件或目录错误2&#xff1a;er…

基于SpringBoot+vue的高校学生成绩管理系统

目录 一、绪论1.1 开发背景1.2 系统开发平台1.2.1 Vue简介1.2.2 IDEA简介1.2.3 MySQL简介 1.3 系统开发环境 二、需求分析2.1 系统需求分析2.2 系统数据流图 三、概要设计3.1 业务流程分析 四、详细设计4.1 系统功能结构图4.2 E-R模型4.3 数据库表设计 五、模块实现5.1 管理员主…

Docker--Docker Image(镜像)

什么是Docker Image&#xff1f; Docker镜像&#xff08;Docker Image&#xff09;是Docker容器技术的核心组件之一&#xff0c;它包含了运行应用程序所需的所有依赖、库、代码、运行时环境以及配置文件等。 简单来说&#xff0c;Docker镜像是一个轻量级、可执行的软件包&…

RabbitMQ的核心组件有哪些?

大家好&#xff0c;我是锋哥。今天分享关于【RabbitMQ的核心组件有哪些&#xff1f;】面试题。希望对大家有帮助&#xff1b; RabbitMQ的核心组件有哪些&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 RabbitMQ是一个开源的消息代理&#xff08;Messag…

[OpenGL] Transform feedback 介绍以及使用示例

一、简介 本文介绍了 OpenGL 中 Transform Feedback 方法的基本概念和代码示例。 二、Transform Feedback 介绍 1. Transform Feedback 简介 根据 OpenGL-wiki&#xff0c;Transform Feedback 是捕获由顶点处理步骤&#xff08;vertex shader 和 geometry shader&#xff0…

【Linux】—简单实现一个shell(myshell)

大家好呀&#xff0c;我是残念&#xff0c;希望在你看完之后&#xff0c;能对你有所帮助&#xff0c;有什么不足请指正&#xff01;共同学习交流哦&#xff01; 本文由&#xff1a;残念ing原创CSDN首发&#xff0c;如需要转载请通知 个人主页&#xff1a;残念ing-CSDN博客&…

什么是Apache日志?为什么Apache日志分析很重要?

Apache是全球最受欢迎的Web服务器软件&#xff0c;支持约30.2%的所有活跃网站。凭借其可靠性、灵活性和强大的功能&#xff0c;Apache数十年来一直是互联网的中坚力量。 一、Apache Web服务器的工作原理 Apache Web服务器的工作原理如下&#xff1a; 接收HTTP请求&#xff1…

Spring Security 6 系列之一 - 开篇入门

之所以想写这一系列&#xff0c;是因为之前工作过程中使用Spring Security&#xff0c;但当时基于spring-boot 2.3.x&#xff0c;其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0&#xff0c;结果一看Spring Security也升级为6.3.0&#xff0c;关键是其风…