《深度探索c++对象模型》第六章笔记
非原创,在学习
6 执行期语意学(Runtime Semantics)
有这样一个简单的案例:
if (yy == xx.getValue())
{// ...
}
其中,xx和yy的定义为:
X xx;
Y yy;
class Y定义为:
class Y {
public:Y();~Y();bool operator==(const Y&) const;// ...
};
class X定义为:
class X {
public:X();~X();operator Y() const; // conversion运算符X getValue();// ...
};
Y类重载了==运算符,形参是Y,在本例中笔记的是yy == xx.getValue();在X类中,有一个conversion运算符,将X对象转换为Y对象,这使得案例成立。
这里会产生一系列的临时变量。
(1)产生一个临时变量Class X object,放置getValue()的返回值
X temp1 = xx.getValue();
(2)产生一个临时变量class Y object,放置operator Y()的返回值
Y temp2 = temp1.operator Y();
(3)产生一个临时变量int object,放置equality(等号)运算符的返回值
int temp3 = yy.operator==(temp2);
最后,适当的destructor 将被施行于每一个临时性的class object身上。这导致我们的式子被转换为以下形式:
// C++伪码
// 以下是条件if(yy == xx.getValue()) ...的转换
{X temp1 = xx.getValue();Y temp2 = temp1.operator Y();int temp3 = yy.operator==(temp2);if (temp3) {// ...}temp2.Y::~Y();temp1.X::~X();
}
略麻烦
6.1 对象的构造和解构( object Construction and Destruction )
一般而言,constructor和destructor的安插都如你所预期:
// c++伪码
{Point point;// 构造函数会被安插在这里// point.Point::Point()// ...// 析构函数会被安插在这里// point.Point::~Point();
}
构造函数的调用放在返回值之前。
全局对象(Global Objects )
有以下片段:
Matrix identity;int main(void)
{// identity必须在此处被初始化Matrix m1 = identity;// ... return 0;
}
C++保证,一定会在main()函数中第一次用到identity 之前,把identity构造出来,而在main()函数结束之前把identity摧毁掉。像identity这样的所谓global object 如果有constructor 和 destructor 的话,我们说它需要静态的初始化操作和内存释放操作.
C++程序中所有的 global objects都被放置在程序的data segment中。如果明确指定给它一个值,object 将以该值为初值。否则object所配置到的内存内容为0。因此在下面这段码中:
int v1 = 1024;
int v2;

初始化全局变量/全局对象
局部静态对象(Local Static Objects)
有以下案例:
const Matrix&
identity() {static Matrix mat_identity;// ...return mat_identity;
}
局部静态对象保证了什么样的语意?
mat_identity的constructor必须只能施行一次,虽然上述函数可能会被调用多次。
mat_identity的destructor必须只能施行一次,虽然上述函数可能会被调用多次。
编译器的策略之一就是,无条件地在程序起始( startup)时构造出对象来。然而这会导致所有的local static class objects都在程序起始时被初始化,即使它们所在的那个函数从不曾被调用过。因此,只在identity()被调用时才把mat_identity构造起来,是比较好的做法(现在的C++ Standard已经强制要求这一点)。我们应该怎么做呢?
以下就是我在 cfront之中的做法。首先,我导入一个临时性对象以保护mat_identity 的初始化操作。第一次处理identity()时,这个临时对象被评估为false,于是constructor会被调用,然后临时对象被改为true。这样就解决了构造的问题。而在相反的那一端,destructor也需要有条件地施行于mat_identity身上,但只有在mat_identity已经被构造起来时才算数。要判断mat_identity是否被构造起来,很简单。如果那个临时对象为true,就表示构造好了。困难的是由于cfront产生C码,mat_identity对函数而言仍然是local,因此我没办法在静态的内存释放函数〈 static deallocation function)中存取它。噢,伤脑筋!解决的方法有点诡异,结构化语言避之唯恐不及:我取出 local object的地址。(当然啦,由于object是 static,其地址在 downstream component中将会被转换到程序内用来放置 global object的 data segment中)。
最后,destructor必须在“与text program file (也就是本例中的 stat_0.c)有关联的静态内存释放函数( staic deallocation function)”中被有条件地调用。
对象数组(Array of Objects)
有以下数组定义:
Point knots[10];
如果 Point 既没有定义一个constructor也没有定义一个destructor,那么我们的工作不会比建立一个“内建(build-in)类型所组成的数组”更多,也就是说,我们只需配置足够的内存以储存10个连续的Point元素。
然而Point的确定义了一个default destructor,所以这个destructor必须轮流施行于每一个元素之上。一般而言这是经由一个或多个runtime library函数达成。
void*
vec_new(void* array, // 数组起始地址size_t elem_size, // 每个class object的大小int elem_count, // 数组中的元素数目void (*constructor)(void*),void (*destructor)(void*, char)
)
其中的constructor和 destructor参数是这个class的 default consructor和default destructor的函数指针。参数array带有的若不是具名数组(本例为knots)的地址,就是0。如果是0,那么数组将经由应用程序的new运算符被动态分配到heap中。参数elem_size表示数组中的元素数目。
Default Constructors 和数组
如果你想要在程序中取出一个constructor的地址,这是不可以的。当然啦,这是编译器在支持vec_new()时该做的事情。
举个例子,在 cfront 2.0 之前,声明一个由 class objects所组成的数组,意味着这个class必须没有声明constructors或一个default constructor(没有参数那种)。一个constructor不可以取一个或一个以上的默认参数值。这是违反直觉的,会导致以下的大错。
这一段没啥结论,就说了之前的一些错误写法
6.2 new 和delete 运算符
运算符new 的使用,看起来似乎是一个单一运算,像这样
int* pi = new int(5);
但事实上它是由以下两个步骤完成:
1 通过适当的new运算符函数实体配置所需的内存:
// 调用函数库中的new运算符
int* pi = _new(sizeof(int));
2 给配置得来的对象设立初始值
*pi = 5;
更进一步地,初始化操作应该在内存配置成功(经由new运算符)后才执行:
// new运算符的两个分离步骤
// given: int* pi = new int(5);// 重写声明
int* pi;
if (pi == _new(sizeof(int))) {*pi = 5; // 成功了才能初始化
}
好像用malloc和new的时候,还没出过错。。。。。。
delete运算符的情况类似。
对象的new也是这样,先申请空间,在初始化,如果处理异常,程序则会稍微复杂点
malloc申请出错返回NULL
new申请出错会抛出异常
针对数组的new语意
针对数组:
int* p_array = new int[5];
vec_new()不会真正被调用,因为它的主要功能是把default constructor施行于class objects 所组成的数组的每一个元素身上。倒是new运算符函数会被调用:
int* p_array = (int*)_new(5 * sizeof(int));
相同的情况
// struct simple_aggr { float f1, f2; };
simple_aggr* paggr = new simple_aggr[5];
vec_new()也不会被调用。为什么呢?因为simple_aggr并没有定义一个constructor或destructor,所以配置数组以及清除p_aggr数组的操作,只是单纯地获得内存和释放内存而已。这些操作由new和 delete运算符来完成就绰绰有余了。
然而如果class定义有一个default constructor,某些版本的vec_new()就会被调用,配置并构造class objects所组成的数组。例如这个算式:
Point3d* p_array = new Point3d[10];
通常会被编译为:
Point3d* p_array;
p_array = vec_new(0, sizeof(Point3d), 10,&Point3d::Point3d,&Point3d::~Point3d);
还记得吗,在个别的数组元素构造过程中,如果发生exception,destructor就会被传递给vec_new()。只有已经构造妥当的元素才需要destructor的施行,因为它们的内存已经被配置出来了,vec_new()有责任在exception发生的时候把那些内存释放掉。
在C++2.0版之前,将数组的真正大小提供给程序的delete运算符,是程序员的责任。
delete [size]p_array;
现在这样写
delete []p_array;
如果类中自己定义了构造函数和析构函数,在new 和 delete的时候,会调用构造函数和析构函数。
最好就是避免以一个base class指针指向一个derived class objects所组成的数组——如果derived class object比其 base 大的话。
Placement Operator new 的语意
有一个预先定义好的重载的( overloaded )new运算符,称为placement operator new。它需要第二个参数,类型为void*。调用方式如下:
Point2w* ptw = new(arena)Point2w;
其中arena指向内存中的一个区块,用以放置新产生出来的 Point2w object.这个预先定义好的 placement operator new的实现方法简直是出乎意料的平凡.它只要将“获得的指针(译注:上例的arena)”所指的地址传回即可:
void*
operator new(size_t, void* p)
{return p;
}
如果它的作用只是传回其第二个参数,那么它有什么价值呢?也就是说,为什么不简单地这么写算了(这不就是实际所发生的操作吗):
Point2w* ptw = (Point2w*)arena;
事实上这只是所发生的操作的一半而已。Placement new operator所扩充的另一半边是将Point2w constructor自动实施于arena所指的地址上:
// c++伪码
Point2w* ptw = (Point2w*)arena;
if (pte != 0)
{ptw->Point2w::Point2w();
}
这正是使placement operator new威力如此强大的原因。这一份码决定objects被放置在哪里;编译系统保证object的constructor会施行于其上。
相关文章:
《深度探索c++对象模型》第六章笔记
非原创,在学习 6 执行期语意学(Runtime Semantics) 有这样一个简单的案例: if (yy xx.getValue()) {// ... } 其中,xx和yy的定义为: X xx; Y yy; class Y定义为: class Y { public:Y();~Y();bool operator(con…...
wolfSSL5.6.3 虚拟机ubuntu下编译运行记录(踩坑填坑)
网上相关教程很多(包括wolfSSL提供的手册上也是如此大而化之的描述),大多类似如下步骤: ./configure //如果有特殊的要求的话可以在后面接上对应的语句,比如安装目录、打开或关闭哪些功能等等 make make install 然后结束,大体…...
JAVA SE -- 第十六天
(全部来自“韩顺平教育”) IO流 一、文件 是保存数据的地方 2、文件流 文件在程序中是以流的形式来操作 流:数据在数据源(文件)和程序(内存)之间经历的路径 输入流:数据从数据…...
基于EIoT能源物联网的工厂智能照明系统应用改造-安科瑞黄安南
【摘要】:随着物联网技术的发展,许多场所针对照明合理应用物联网照明系统,照明作为工厂的重要能耗之一,工厂的照明智能化控制,如何优化控制、提高能源的利用率,达到节约能源的目的。将互联网的技术应用到工…...
docker-compose启动tomcat服务
docker-compose启动tomcat服务 编写docker-compose.yaml文件 version: "3.1" services:tomcat: restart: always image: tomcat:8.0.52 container_name: tomcat ports:- 8082:8080 environment:TZ: Asia/Shanghai volumes:- /usr/local/webapps/:/usr/local/t…...
10.多线程
文章目录 10.1简述线程、程序、进程的基本概念。以及他们之间关系是什么?10.2线程有哪些基本状态? 10.1简述线程、程序、进程的基本概念。以及他们之间关系是什么? 线程与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程…...
【有关数据库的编码格式和导出备份】
问题1:前端页面可以正常插入数据到数据库mysql中,但是却显示不了数据库中的数据内容? 分析:通过尝试,当数据插入的全部都是英文时,可以正常显示数据,但是出现中文时,则连带着全部数…...
直播招聘小程序解决方案
项目开发愿景 介绍工作拿佣金,Boss直播现真身。做为直播招聘的新平台,让求职和招聘变得更简单!企业发布招聘视频,展现公司环境与实力,开通会员可以直播招聘、在线面试功能;求职者刷视频可以刷到工作…...
HadoopWEB页面上传文件报错Couldn‘t upload the file course_info.txt
HadoopWEB页面上传文件报错Couldn’t upload the file course_info.txt 右键F2检查发现:文件上传PUT操作的IP地址是节点IP别名识别不到导致 解决方法:在WEB页面访问浏览器所在机器上面配置hosts映射地址(注意:配置的是浏览器访问的地址不是hadoop节点所在…...
面试热题(倒数第k个结点)
输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。 例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表…...
EVE-NG MPLS 静态 LSP
1 拓扑 2 配置步骤 2.1 配置接口IP 和路由 LER1 interface GigabitEthernet1/0ip address 10.1.1.1 255.255.255.0quitinterface GigabitEthernet2/0ip address 11.1.1.1 255.255.255.0quitip route-static 21.1.1.0 24 10.1.1.2VPC1 ip 11.1.1.100/24 11.1.1.1 配置完成后…...
华秋亮相2023世界汽车制造技术暨智能装备博览会,推动汽车产业快速发展
洞悉全球汽车产业格局,前瞻业界未来趋势。2023年7月27日-30日,时隔三年,重聚武汉国际博览中心,2023世界汽车制造技术暨智能装备博览会盛大开幕。深耕汽车行业多年的世界汽车制造技术暨智能装备博览会,掀起行业热点新高…...
华为OD机试真题【开心消消乐】
1、题目描述 【开心消消乐】 给定一个N行M列的二维矩阵,矩阵中每个位置的数字取值为0或1。矩阵示例如: 1100 0001 0011 1111 现需要将矩阵中所有的1进行反转为0,规则如下: 1) 当点击一个1时,该1便被反转为…...
txt去重
目录 txt去重 让我解释一下代码的逻辑: for a in [a.strip(\n) for a in list(f_read)]: txt去重 f_read open(r./1.txt, r, encodingutf-8) f_write open(r./2.txt, w,encodingutf-8) data set() for a in [a.strip(\n) for a in list(f_read)]:if a not in …...
系统集成测试与验收
功能性测试:测试系统应提供的每一个功能和安全性限制,检查系统是否已 正常实现所有功能。 连通性测试:测试网络上任意站点间是否能够相互传输数据,测试各个终端 能否登录中心服务器,并访问数据库,对数据库…...
ElementPlus文件上传 ,在上传前钩子中判断文件是否为图片
在ElementPlus中,可以使用beforeUpload属性来指定上传文件之前的钩子函数,在该函数中可以对文件进行判断并进行相关操作。 首先,在data中定义一个isImage变量来记录文件是否为图片,初始值为false。然后,在钩子函数中判…...
涂鸦智能获Matter Non-VID Scoped PAA资质 助力开发者拥抱Matter生态
今年5月,全球化IoT开发者平台涂鸦智能(NYSE: TUYA,HKEX: 2391)正式生成Tuya Matter PAA密钥根,并于7月,成功通过了连接标准联盟和第三方MA机构审查而上线。自此,涂鸦正式成为全球同时提供支持Ma…...
nsqd的架构及源码分析
文章目录 一 nsq的整体代码结构 二 回顾nsq的整体架构图 三 nsqd进程的作用 四 nsqd启动流程的源码分析 五 本篇博客总结 在博客 nsq整体架构及各个部件作用详解_YZF_Kevin的博客-CSDN博客 中我们讲了nsq的整体框架,各个部件的大致作用。如果没看过的&…...
LeetCode解法汇总344. 反转字符串
目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣 描述: 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数…...
【C语言基础】数组的高级应用(上)
文章目录 一、数组的概念1.1 基本理解1.2 从内存角度理解数组1.3 从编译器角度理解数组 二、数组的定义2.1 第一种:完全初始化2.2 第二种:不完全初始化 三、访问数组的两种方式3.1 第一种:数组的方式依次访问3.2 第二种:指针的方式…...
从USB转TTL接线到手机热点配网:ESP8266无线通信保姆级避坑指南(附软件包)
从USB转TTL接线到手机热点配网:ESP8266无线通信保姆级避坑指南 当你第一次拿起ESP8266模块时,可能会被这个小巧的Wi-Fi模块惊艳到——它只有指甲盖大小,却蕴含着强大的无线通信能力。但很快,这种惊艳就会变成困惑:为什…...
Ventoy终极指南:一个U盘启动所有系统,告别重复格式化烦恼 [特殊字符]
Ventoy终极指南:一个U盘启动所有系统,告别重复格式化烦恼 😎 【免费下载链接】Ventoy A new bootable USB solution. 项目地址: https://gitcode.com/GitHub_Trending/ve/Ventoy 还在为每次安装系统都要重新制作启动盘而烦恼吗&#x…...
古戏台构件声学特性的时域有限差分方法【附模型】
✨ 长期致力于时域有限差分法、窑洞、戏台、八字墙、共形技术研究工作,擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流,点击《获取方式》 (1)曲面共形网格快速生成算法: …...
告别虚频困扰:用VASP+DynaPhoPy搞定高温材料声子谱的保姆级教程
高温材料声子谱计算实战:从虚频困境到非谐解决方案 引言:虚频问题的根源与突破路径 在计算材料学领域,声子谱分析是理解材料动力学稳定性和热力学性质的核心手段。然而许多研究者都遭遇过这样的困境:对实验合成的材料进行简谐近似…...
【2026最新】应对Turnitin查重:实测5大英文查降AI宝藏工具,一站式搞定初稿
现在的英文初稿,无论是期刊文章、SCI 还是普通的 Course Essay,基本都需要评估内容的原创度,进行文章 AI 率检测。很多伙伴以为纯手敲就能过,结果一查数据依然不尽如人意。 针对英文内容,咱们必须使用专门的英文检测和…...
BurpSuite 2025插件开发JDK版本兼容性实战指南
1. 为什么BurpSuite插件开发环境总在JDK版本上翻车?你是不是也经历过:下载好BurpSuite最新版2025.4,兴冲冲打开插件开发文档,照着官方示例写完第一个HelloWorld插件,一编译——java.lang.UnsupportedClassVersionError…...
2026年,揭秘那些真正安全的原生态食材厂家你不可不知的秘密
随着人们生活水平的提升以及对健康的日益重视,选择真正安全的原生态食材已经成为许多人购买食物的标准。但市场的繁杂使得甄别真正安全的食材厂家变得愈加困难。今天,我将通过几个关键角度,为大家揭秘那些真正安全的原生态食材厂家的秘密&…...
Midjourney锐化效果失效真相(2024官方未公开的渲染管线瓶颈解析)
更多请点击: https://intelliparadigm.com 第一章:Midjourney锐化效果失效真相(2024官方未公开的渲染管线瓶颈解析) 自2024年V6.2版本起,大量用户反馈 --stylize 与 --sharp 参数组合下图像边缘锐化效果显著弱化&am…...
《我看见的世界:李飞飞自传》第1-6章阅读笔记:从移民少女到AI教母的“看见“之旅
前言 当我们谈论人工智能时,我们谈论的是算法、数据、算力,是那些冰冷的代码和复杂的模型。但在《我看见的世界:李飞飞自传》中,李飞飞用她独特的视角告诉我们:AI的本质,是人类对"看见"世界的渴望…...
智能体所有权与版权:AI Agent Harness Engineering 创造的作品归谁所有?
1. 标题选项 《AI Agent创作版权迷局破解:从Harness工程原理到所有权划分的完整指南》 《智能体作品归谁?AI Agent Harness Engineering场景下的版权规则深度拆解》 《告别权属纠纷:一文搞懂AI Agent生成内容的所有权、版权与收益分配规则》 《Harness工程视角下的AI创作权:…...
