C++基本功和 Design Pattern系列(3) ctor & dtor

AMDGPU SVM VRAM Migration 实现详解 AMD正在基于DRM SVM框架重构SVM实现,该框架即将广泛应用。本文分析了AMD开发者提交的POC验证版本的技术方案。该架构分为三层:AMDGPU SVM映射层、DRM Pagemap通用框架层和AMDGPU迁移后端硬件驱动层。系统涉及三个地址空间转换:VRAM分配器空间、HPA/PFN空间和GPU PTE地址空间。关键数据结构包括设备级迁移基础设施amdgpu_pagemap、迁移临时BO包装器amdgpu_svm_bo等。该方案通过地址空间转换实现VRAM迁移功能,目前仍处于POC阶段,设计可能变更 阅读详情
======================================================
 
大家请把我的文章当参考,详细内容  还请参照 权威书籍 
 <c++ programming language>如果文中有错误和遗漏,
 请指出,Aear会尽力更正, 谢谢!
======================================================
最近实在是太忙了,无工夫写呀。只能慢慢来了。呵呵,今天Aear讲的是class.ctor 也就是constructor, 和 class.dtor, destructor. 相信大家都知道constructor 和 destructor是做什么用的,基本功能我就不废话了。下面先说效率的问题,让我们看个简单的例子:

class SomeClass;   // forward declaration

class AnotherClass {
private:
    SomeClass SomeClassInstance;
public:
    AnotherClass(const SomeClass & Para) { SomeClassInstance = Para; };
    ~AnotherClass();
};

也许这是很多初学者经常写出来的代码,Aear以前也写过。让我们来看看这段代码有什么问题。

首先需要说明的是,在一个class实例化之前,所有的member都会被初始化,如果member是个class,那么那个class的constructor就会被调用。也就是说,在运行AnotherClass的constructor之前,SomeClass的constructor就已经运行了。接下来的代码里,SomeClassInstance又被重新执行了次 = 操作。也就是说,我们在给SomeClassInstance附初值的时候,调用了2次SomeClass的method. 这个浪费也太大了,比较标准的方式是使用初始化列表,如下:

    AnotherClass (const SomeClass & Para): SomeClassInstance(Para) {};
如果有多个类成员,可以用","来分割,如:

    AnotherClass (const SomeClass & Para1, UINT32 Para2):
                   SomeClassInstance(Para1),
                   SecondAttr(Para2),
                   ThirdAttr(Para3) {};
值得注意的是, 类成员的初始化顺序和在类中的声明顺序应该一致。这个是有compiler来控制的,并不根据你在AnotherClass的constructor中提供的初始化顺序来进行。所以,如果你想先初始化ThirdAttr,然后把ThirdAttr传到SecondAttr作为初始化参数,是会失败的。只有改变声明顺序才会成功。

同理,在声明类变量被附初值的时候,使用拷贝构造函数,效率更高:

=====错误=====
class x1;
x1 = x2;

=====正确=====
class x1(x2);

===================分割线===================

从上面的例子可以看到,几乎所有的class,都需要提供拷贝构造函数,也就是 className(const className &)。同时值得注意的是,如果提供了拷贝构造函数,一般也就需要提供 "="操作,也就是 className & operator = (const className &),说到 operator =, 也有必要强调下implicit type conversion的问题,这将会在以后的章节张有详细描述。至于为什么要提供 operator =,举个简单的例子:
 
class1 {
public:
    class1() { p = new int[100]; };
    ~class1() { delete[] p; };
private:
    char* p;
} x1, x2;

如果class1不提供operator =, 那么运行 x1 = x2的时候,C++会运行最基本的拷贝操作,也就是 x1.p = x2.p,那么在x1被释放的时候,delete p;被执行。这时候 x2再要访问p,p已经变成非法指针了。 也许有人会说,我才不会用x1 = x2这么危险的操作,那让我们看看更加隐性的操作吧,例子如下:

void func(class1 Para) {...};

func(x1);

这时候,c++会调用class1的拷贝构造函数,来把参数从x1里拷贝到Para,如果class1没有提供copy constructor,那么c++就执行简单拷贝工作,也就是 Para.p = x1。当func返回的时候,Para被释放,调用 Para.~class1(),并且delete p;那么x1.p就变成非法指针了。

这样大家就知道为什么要同时提供copy constructor和 operator =了吧。特别是在class里有指针的情况下,必须提供以上2个method。如果不想提供,可以把他们设为private,代码如下:

class1 {
...
private:
    class1 (const class1 &);
    class1 & operator = (const class1 &);
}
这样别人在执行 = 和 func()的时候就会报错了。

还有,在声明构造函数的时候,单参数的构造函数,最好都用explicit来声明,例如:

class1 {
public:
    class1(int Para) {...}
    ...
};

其中class1(int Para)是个单参数的构造函数,如果执行下列操作,如:

class1 x1 = 2;

的时候,因为2不是class1,所以c++会用隐性的类型转换,也就是把2转换成class1,因此会调用class1(2),然后用operator = 符值给 x1. 这种操作经常会产生很多问题。比如如果我们提供了 operator == ,那么 在 if(x1 == 2)的时候,c++也会进行类似的操作,可能会产生我们不需要的结果。所以,对于这种单参数的constructor 最好做如下声明:

explicit class1 (int Para) {...}

这样做再执行 class1 x1 = 2;的时候就会报错了,explicit的意思就是C++ 的compiler不能做隐性类型转换,必须由程序员做type cast,比如:

class1 x1 = static_cast<class1>(2) 才会成功。

===================分割线===================
在运行constructor的时候,值得注意的一点就是,如果在constructor里,要初始化会throw exception的代码,一定要在constructor里catch。比如:

class1 {
    class1()
    {
       pInt = new int[100];
       try {
           pClass2 = new pClass2;
       }catch(...)
       { delete pInt; throw; };
     }
}

大家看的明白了吧,如果不catch pClass2的exception,pInt分配的内存就不会释放,因为constructor如果失败,c++是不会调用destructor的。

===================分割线===================
最后关于destructor,需要注意的是,如果是被继承的base class,destructor一定要是virtual。比如:

BaseClass ()
{
public:
    BaseClass();
    virtual ~BaseClass();
}

DerivedClass : public BaseClass()
{
public:
    DerivedClass();
    ~DerivedClass();
}

BaseClass * pBase = static_cast<BaseClass *>(new DerivedClass());
delete pBase;

如果BaseClass的destructor是virtual,那么正确的ctor dtor调用顺序是:

BaseClass();
DerivedClass();
~DerivedClass();
~BaseClass();

如果不是Virtual,调用顺序是:

BaseClass();
DerivedClass();
~BaseClass();

也就是说,DerivedClass的派生类不能被正确调用,这主要是因为在delete的时候c++并不知道你delete的是 DerivedClass, 因此需要把BaseClass的 dtor 设置成 virtual, 这样可以使用 vptr在 vtbl中查找 destructor,从而能够正确的调用destructor。

===================分割线===================
从上面的例子大家也看出来了,如果是派生类,那么就要调用基类的constructor,在多层次的派生类创建过程中,所以基类的constructor都要被调用。 destructor同理。因此要想提高效率,可以在关键代码短使用非派生类。

也许有人会说,所有的constructor和destructor都被compiler inline了,但是即使是inline并且base class的constructor中不进行任何操作,c++也要为每个类设置vptr,也是有不需要的overhead。当然,我们得到效率的同时,失去的是可扩展性,良好的程序层次结构等等,大家要根据具体情况来权衡。


DeerFlow 系列教程 附录 | 核心文件索引、官方文档索引与推荐阅读顺序 DeerFlow 系列教程 附录本附录汇集了 DeerFlow 项目的核心文件索引、官方文档索引和推荐阅读顺序三份速查资料,方便读者在日常开发和学习中快速定位关键代码与文档。内容按实际项目目录结构整理,所有路径均基于 DeerFlow 2.0 版本验证。 阅读详情

相关推荐

HX720数据采集实战:从硬件连接到姿态解析(含避坑指南)

本文详细介绍了HX720高精度ADC芯片在数据采集与姿态解析项目中的实战应用。内容涵盖从硬件电路设计、驱动源码编写与优化,到原始数据处理、校准以及最终姿态角度计算的完整流程,并提供了关键的避坑指南和调试技巧,帮助开发者高效完成从传感器信号到可用姿态数据的转换。

i8j9k0l1的博客 488

C++基本功和 Design Pattern系列 ctor & dtor

最近实在是太忙了,无工夫写呀。只能慢慢来了。呵呵,今天Aear讲的是class.ctor 也就是constructor, 和  class.dtor, destructor. 相信大家都知道constructor 和 destructor是做什么用的,基本功能我就不废话了。下面先说效率的问题,让我们看个简单的例子:class SomeClass;   // forward declaratio

杨德龙的专栏 1万+

使用 Restart Extension 继续解决 Ansys 机械分析

您正在执行复杂或大型的多步有限元分析,突然,您意识到经过数小时的求解后,您需要添加或修改边界条件。在本篇博文中,您将了解如何利用 Ansys Mechanical 中的 RestartAnalysis 扩展来扩展多步分析,方法是合并额外的时间步骤和边界条件,而不会丢失已计算的结果。幸运的是,在 Mechanical 中,有一种直接的方法可以实现这一点,而不会损害您之前的结果,而这在添加新边界条件和使用重新启动点时经常发生。得到的结果符合预期,您可以看到施加的力产生的这两个部分之间的相对位移。

jkh920184196的博客 1233

深度探索c++对象模型(5):ctor、dtor、copy

一、无继承的对象构造: 类中包含的都是POD,则该类的ctor、dtor、copy都是trivial,初始化、拷贝、回收该类型对象,编译器不会产生对应的ctor、dtor、copy。 二、加入虚函数: 由于构造函数需要初始化vptr,因此ctor、copy是nontrivial,dtor是trivial 在一个类B中使用了其他类A,并且该类有ctor、dtor、copy,则B的ctor、dtor、copy都是nontrivial。 三、虚拟继承: 由最底层的class对Point进行初始化 四、vpt

ehuangdan5864的博客 6663

RK3568 解决MIPI屏幕开机只显示uboot logo的问题

之前写过一篇文章介绍了RK3568驱动MIPI屏幕的方法,这次产品迭代,硬件改版,选型的新的屏幕了。所以再次开启调试屏幕的过程。本以为会和上次一样会轻车熟路,事情总是事与愿违,同样的路,遇到新的坑。

fhqlongteng的博客 5426

基于人脸识别的课堂考勤系统 tkinter+openpyxl+face_recognition

基于face_recognition库实现人脸考勤系统功能。利用Python的tkinter模块来设计考勤系统的图形化界面,此外结合openpyxl模块,实现将学生的信息和考勤打卡数据保存到表格中,方便查看和调用。该系统具备“刷脸打卡”、“新学生注册”等功能。............

lyx4949的博客 6965

c++三大函数:拷贝构造(copy ctor)、拷贝赋值(copy op)、析构函数(dtor)

Class的两个经典分类 Class without pointer member(s) complex Class with pointer member(s) string String class 以下为头文件string.h内容 #ifndef _MYSTRING_ #define _MYSTRING_ //类中进行字符串的构造 class String { ... }; //谨记切勿忘分号 //字符串所具备的功能 String::function(...) ... Global-functi

一个搬运知识的笨小孩 2741

霍尔式流量计背后的技术和算法

例如,在一项实验中,当流量低于最小操作范围(0.250 L/min)时,误差比其他流量大,但仍然在95%的精度范围内可接受。例如,在Honeywell电子学的测试中,使用30英寸水柱的压力计和热电偶测量气体特性,记录并计算实际和理论质量流量,以确定修正系数。霍尔式流量计的校准系数是通过一系列精确的测量和计算步骤确定的,以确保其测量结果的准确性和可靠性。霍尔式流量计的校准系数是通过严格的环境条件、精确的测量步骤和实验数据确定的。其中,Qs是标尺介质的流量,K是修正系数,Qm是用户介质的流量。

百态·数智思维 | 聚焦大数据、量化与未来AI 1234

c++(六)、对象和类(四)

一、析构、友元与深浅拷贝 1、析构函数(destructor) 析构函数与构造函数正好相反,析构函数用来销毁对象。 下面列出构造函数(ctor)和析构函数(dtor)的对比: (1)ctor当对象创建时使用,dtor当对象销毁时使用; (2)ctor的原型:C::C(arguments);dtor的原型:C::~C(); (3)ctor的默认函数原型:C::C()或参数带有默认值;dtor的默认函数原型:C::~C(); (4)当都没有显示声明时,ctor和dtor都有创建一个...

GuiHuaCaiZi的博客 522

手把手教你学Simulink——基于Simulink的Boost变换器电流模式控制(峰值电流控制)建模示例

本文详细介绍了基于Simulink的Boost变换器峰值电流模式控制建模方法。首先分析了Boost变换器在CCM模式下的工作原理及电流控制优势,重点阐述了斜坡补偿的必要性。通过分步指导搭建Simulink模型,包括主电路、电流采样、RS触发器和电压外环PI控制器等核心模块。仿真验证了系统在启动、负载突变和输入电压跌落等工况下的优异性能,输出电压稳定在48V±0.5V。文章还总结了工程实践要点,并提出了数字实现等扩展方向。该建模方法为电力电子高级控制策略的工程验证提供了有效途径。

MHD0815的博客 249

198、影像系统设计评审流程:从需求评审到 EVT、DVT、PVT 各阶段的关注重点

本文详细介绍了影像系统从需求评审到EVT、DVT、PVT各阶段的设计评审流程及关键点。作者通过实际案例(如IMX766模组偏紫问题)强调硬件工艺的重要性,指出影像系统是功能定义与物理实现的反复拉锯过程。文章分阶段解析:需求评审需将模糊需求转化为物理参数;架构评审要明确接口定义和时序约束;EVT阶段重点关注模组一致性和基础链路;DVT阶段需平衡算法调优与硬件验证;PVT阶段则以量产一致性为核心。最后提出建立"边界条件确认表"和"健康度看板"等实用建议,强调工程师需具备从表象追溯硬件根源的物理直觉。全文贯穿实战

sundong_81的博客 218

ctor/dtor 与线程安全

ctor/dtor 与线程安全 当一个对象能被多个线程同时看到,那么对象的销毁时机就会变得模糊不清,可能出现多种竞态条件: 在即将析构一个对象时,从何而知是否有另外的线程正在执行该对象的成员函数? 如何保证在执行成员函数期间,对象不会在另一个线程被析构? 在调用某个对象的成员函数之前,如何得知这个对象还活着? 现在以 shared_ptr 一劳永逸地解决这些问题 线程安全的定义 依据《Java&nbsp;并发编程实践》/《Java&nbsp;Concurrency&nbsp;in&nbsp

qq_41105501的博客 1252

把 SAP ABAP ALE 与 IDoc 玩明白:从架构、配置到排错的一套闭环方法

本文介绍了SAP集成中ALE与IDoc的核心概念与实战应用。ALE作为SAP分布式应用框架,通过异步消息机制实现系统间数据交换,其三层架构隔离业务与传输细节。IDoc作为标准化消息容器,包含控制、数据和状态记录。文章详细解析了配置要点(端口、伙伴参数)、处理流程(Process Code)、排错工具(BD87、WE09)及同系统测试方法,并提供了发送程序代码骨架。通过架构认知→配置→开发→运维的完整路径,帮助读者掌握ALE/IDoc的实际操作技能。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 223

C++基本功和 Design Pattern系列 ctor & dtor (转)

最近实在是太忙了,无工夫写呀。只能慢慢来了。呵呵,今天Aear讲的是class.ctor 也就是constructor, 和  class.dtor, destructor. 相信大家都知道constructor 和 destructor是做什么用的,基本功能我就不废话了。下面先说效率的问题,让我们看个简单的例子: class SomeClass;   // forward declaratio

dragoo1的专栏 1120

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

[转]C++基本功和 Design Pattern系列 ctor & dtor

今天Aear讲的是class.ctor也就是constructor,和 class.dtor,destructor.相信大家都知道constructor和destructor是做什么用的,基本功能我就不废话了。下面先说效率的问题,让我们看个简单的例子: classSomeClass;//forwarddeclaration classAnotherClass{pr...

weixin_30737363的博客 116

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

【转载】C++基本功和 Design Pattern系列 ctor & dtor

最近实在是太忙了,无工夫写呀。只能慢慢来了。呵呵,今天Aear讲的是class.ctor也就是constructor,和 class.dtor,destructor.相信大家都知道constructor和destructor是做什么用的,基本功能我就不废话了。下面先说效率的问题,让我们看个简单的例子: classSomeClass;//forwarddeclaratio...

weixin_30564901的博客 220

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex&trade;-M4F 内核的信息,请参见《Cortex&trade;-M4F 技术参考手册》。

C++基本功和 Design Pattern系列 Exception

说到Exception就要说下相关的Error Handling. 比较常用的Error Handling一般有如下几种类方式:    1. Return value    2. Assert    3. Debug Output    4. Exception相对于其他三种错误处理方式, Exception更加容易使用,而且使得错误代码相对集中,同时使得独立函数库的开发更加方便。同样,对于C

杨德龙的专栏 1128

深度探索C++对象模型-第二章

构造函数语意学 一 默认ctor的构造操作 在4种情况下,编译器会为未声明ctor的类合成一个默认的ctor。 1 带有默认ctor的成员类对象 如果一个类内含一个或一个以上的成员类对象,那么类的每一个ctor必须调用每一个成员类的默认ctor,编译器会扩张已经存在的ctor,在其中插入一些代码,使得用户写的代码被执行前,先调用必要的默认ctor。调用的顺序是这些类对象在类中声明的顺序...

7now_的博客 1106

《C++面向对象高级开发》上篇

《C++面向对象高级开发》上篇

小小博客 1099

c++---constructor(ctor,构造函数)

constructor(ctor,构造函数) : 两种表示方法:

chen_zan_yu_的博客 2006

C++面向对象高级编程(上)

实现前面声明的函数。

weixin_73869176的博客 349

C++候捷课程笔记与补充(学习至03构造函数)

1、 c++编程简介 你需要的基础: 变量(variables) 类型(types):int,float,char,struct 作用域(scope) 循环(loops):while,for 流程控制:if-else,switch-case 我们的目标: 在C++中,我们通过定义一个类(class)来定义自己的数据结构。一个类定义了一个类型,以及与其关联的一组操作。 C++中每一个单元就是class,其中class的经典分类:带有指针的和不带指针的。 对于单一的class的设计叫做Object Based

qq_47991775的博客 390

拷贝构造函数、拷贝赋值函数之间的关系(如何规范设计带指针数据的类)—HJ-record03

拷贝构造函数 拷贝赋值函数 构造与析构函数 带指针数据的类的设计规范要求

恋蛩音的博客 866

C++中的trivial和non-trivial构造/析构/拷贝/赋值函数及POD类型

trivial意思是无意义,这个trivial和non-trivial是对类的四种函数来说的: ◦ 构造函数(ctor) ◦ 复制构造函数(copy) ◦ 赋值函数(assignment) ◦ 析构函数(dtor)

GoddessNaa的博客 2051

【C++】侯捷C++面向对象高级编程(上)

C++面向对象高级编程前言C++ Programs代码基本形式文件类型头文件写法头文件布局class1——complex类的声明inline——内联函数class访问级别(access level)构造函数(ctors)构造函数特有语法构造函数放到private?常量成员函数const member functions参数传递返回值友元friend同一个class的各个object互为友元操作符重载operator overloading(成员函数)操作符重载operator overloading(非成员

半生瓜のblog 2312

机器学习进阶-目标跟踪-KCF目标跟踪方法 1.cv2.multiTracker_create(构造选框集合) 2. cv2.TrackerKCF_create(获得KCF追踪器) 3. cv2.re...

1. tracker = cv2.multiTracker_create() 获得追踪的初始化结果 2.cv2.TrackerKCF_create() 获得KCF追踪器 3.cv2.resize(frame, (w, h), cv2.INTER_AEAR) # 进行图像大小的重新变化参数说明:frame表示输入图片,(w, h) 表示变化后的长和宽, cv2.INTER_AEAR表示插值的方...

weixin_33843409的博客 7185
上一篇: 背单词的五大诀窍
下一篇: C++基本功和 Design Pattern系列(2)
BlueSy2008
博客等级 码龄20年 26粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值