More Effective C++ 35个改善编程与设计的有效方法笔记与心得 1

一. 基础议题

条款1:仔细区别 pointers 和 references

‌‌‌‌  这是一个常见的问题。指针(pointers)和引用(references)都是C++面向对象编程中常用的概念,虽然他们在某些方面表现得很相似,但是其实他们有一些重要的区别。

1. 初始化

  • 指针可以在任何时候被初始化,而且可以多次重新赋值,指向不同的对象或值。
  • 引用在创建时必须被初始化,并且一旦被初始化后就不能改变目标对象。换句话说,引用一旦绑定到一个对象上,就不能重新赋值引用到另一个对象。

2. Null值

  • 指针可以为null,表示它没有指向任何对象。
  • 引用不能为null,必须始终链接到一个已经存在的对象。

3. “解引用"与"间接访问”

  • 指针需要被"解引用"以访问其指向的值(使用*操作符)。
  • 引用不需要特别的语法就可以访问其关联的对象,可以像访问普通变量一样操作引用。

4. 内存

  • 指针本身也有一个内存地址,并占据内存空间。
  • 引用不占用实际内存,只是一个别名。

5. 指针的指针与引用的引用

  • 可以有指向指针的指针,甚至有指向指针的指针的指针等等。
  • C++规定,没有引用的引用

‌‌‌‌  总的来说,如果需要一个变量与另一个变量共享/链接同一值,并且不需要修改链接的话,引用通常是更好的选择。相反,如果你需要存储空值NULL,或者需要在不同的时间点指向不同的对象或者更改指向,则需要使用指针。

条款2:最好使用C++转型操作符

C++提供了四种类型转换操作符:static_castdynamic_castconst_castreinterpret_cast。各自都有特定的用途,你应该根据具体的情况选择使用哪一种。

  1. static_cast:这是最常用的转型操作符,可以用于各种简单的、非多态类型之间的转换,比如基础数据类型(如int到float,float到int),同一继承层级中的上下转型等。

  2. dynamic_cast:主要用于类层次间的向上和向下转换。只有当所涉及的类都是多态的(即,至少有一个虚函数)时才可以使用。如果转换失败,dynamic_cast会返回null。

  3. const_cast:用于将const对象转为非const对象,或者将volatile对象转为非volatile对象。但这并不意味可以通过const_cast修改const对象的值,因为那通常會是未定义的行为。

  4. reinterpret_cast:进行低层次的类型转换,比如将一个指针转换为一个整数,或者将一个类型的指针转换为另一个不相关类型的指针。应谨慎使用,因为其结果很可能取决于具体实现,而且在不同的机器和编译器上可能会有不同的结果。

以上就是C++中的四种转型操作符。值得注意的是,应该优先使用C++的这四种类型转换操作符,而不是C风格的类型转换,因为C++的类型转换操作符更易于找到,也更易于理解和控制。

这里再解释一下volatile对象:
‌‌‌‌  volatile是C++中的一个关键字,它用来修饰变量,表示这个变量可能会在外部,而非程序代码本身,被意外改变。对于被volatile关键字修饰的变量,编译器将会做两件事:

  1. 它将确保不会因为编译器的优化策略而调整对这个变量的读取和写入的顺序。也就是说,编译器不会将这些操作进行缓存或者重排,而是每次都会直接在内存中进行。

  2. 它通知编译器对这个变量的操作不可省略。也就是说,即使同一个值被写入多次,或者读取后的值没有被使用,编译器都不可以省略这些 seemingly redundant的操作。

常见的场合如下:

  • 并发编程:当多个线程可能会访问和修改同一个数据项时,这个数据项应该被声明为volatile。

  • 硬件访问:当一个变量可能被外部之外的事物修改,比如:硬件寄存器,应该将该变量声明为volatile。

  • 用于实现特殊的内存映射,例如某些特殊的硬件设备的内存区域。

请注意,尽管volatile可以防止编译器的某些优化,但它并不是线程安全的解决方案。在多线程环境中进行操作时,需要额外的同步工具(如互斥锁,信号等)来保证线程安全。

条款3:绝对不要以多态(polymorphically)方式处理数组

‌‌‌‌  这句话其实是建议我们在使用含有多态性质的数组(即,数组元素是基类的指针,但实际指向不同的子类对象)时需要格外小心。

‌‌‌‌  当我们处理传统的数组时,编译器会做很多工作来帮助我们,例如正确地识别并管理数组中元素的大小和布局。但是当我们使用多态数组时,这些编译器的帮助就不再适用,我们需要手动管理元素的生命周期,包括它们的创建和销毁。

‌‌‌‌  如果我们像处理普通数组一样处理多态数组,而没有正确管理这些对象的生命周期,就可能会导致一些问题,如内存泄漏或者对象的“切片”

‌‌‌‌  对象的“切片” 是一个常见的问题,发生在当我们直接把一个子类对象赋值给一个基类对象时。子类对象的“基类部分”会被复制到基类对象中,而子类特有的部分则会被切掉,造成数据丢失。

例如以下代码:

Base array[10];
Derived d;array[0] = d; // 对象切片, 把派生类对象赋值给基类对象, 丢失了派生类特有的数据。

‌‌‌‌  解决上述问题的常见策略是使用容器类(如vectorarray)存储指向基类的指针,并使用new创建对象,delete删除对象,从而确保每个对象都正确地创建和销毁。

std::vector<Base*> array;
array.push_back(new Derived());
...
delete array[0]; // 不能忘记删除对象以防止内存泄漏

‌‌‌‌  所以,"绝对不要以多态方式处理数组"的主要含义是,我们在使用多态数组时必须要更加小心,以防止上述的问题发生。

条款4:非必要不提供default constructor

‌‌‌‌  这句话的含义是,除非特别需要,否则应避免提供默认构造函数

‌‌‌‌  在C++中,默认构造函数是一个没有任何参数的构造函数,或者,所有参数都有默认值的构造函数。其他语言中同样也有类似的概念。

‌‌‌‌  默认构造函数被调用的情况包括如下几种:创建新对象时没有提供任何参数创建类的数组时类的派生类的构造函数中调用基类的构造函数,但没有提供任何参数。

‌‌‌‌  通常,如果给定的类有一些必须要满足的初始条件或者属性,那么为了避免默认构造函数创建出未初始化或者部分初始化的对象,我们可能会选择不提供默认构造函数。

‌‌‌‌  比如说:假设我们有一个表示分数的类Fraction。每个Fraction对象都有两个成员变量,分子(numerator)和分母(denominator)。在这个情况下,我们可能不希望 提供一个默认构造函数 Fraction(),因为这样可能会创建出一个分母为0的对象,这在数学上是没有意义的,因此我们更希望用户必须手动提供分子和分母。

‌‌‌‌  所以,"非必要不提供default constructor"主要是为了防止创建未初始化或部分初始化的对象,提高代码的健壮性。但是,具体是否需要提供默认构造函数,还需要根据类对象的具体需求来决定。

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

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

相关文章

深入Symfony事件调度器:掌控应用程序的核心动力

&#x1f39a;️ 深入Symfony事件调度器&#xff1a;掌控应用程序的核心动力 &#x1f680; Symfony是一个高度灵活的PHP框架&#xff0c;以其组件化和可扩展性而闻名。在Symfony中&#xff0c;事件调度器&#xff08;Event Dispatcher&#xff09;是一个强大的工具&#xff0…

Github Page 使用手册(保姆级教程!)

搭建个人网站&#xff1f;没有服务器&#xff1f;那不如尝试一下 Github Page &#xff01; 最近我正好在搭建个人网站&#xff0c;于是就写一篇博客来详细介绍 Github Page 的使用、部署方式吧&#xff01; 一、进入 Github 访问&#xff1a;github.com 如果你没有 github…

Linux中彩色打印

看之前关注下公众号呗 第1部分&#xff1a;引言 1.1 Python在文本处理中的重要性 Python作为一种广泛使用的高级编程语言&#xff0c;以其简洁的语法和强大的功能在文本处理领域占有一席之地。无论是数据清洗、自动化脚本编写&#xff0c;还是复杂的文本分析&#xff0c;Py…

【第9章】MyBatis-Plus持久层接口之SimpleQuery

文章目录 前言一、使用步骤1.引入 SimpleQuery 工具类2.使用 SimpleQuery 进行查询 二、使用提示三、功能详解1. keyMap1.1 方法签名1.2 参数说明1.3 使用示例1.4 使用提示 2. map2.1 方法签名2.2 参数说明2.3 使用示例2.4 使用提示 3. group3.1 方法签名3.2 参数说明3.3 使用示…

RHCE四---web服务器的高级优化方案

一、Web服务器&#xff08;2&#xff09; 基于https协议的静态网站 概念解释 HTTPS&#xff08;全称&#xff1a;Hyper Text Transfer Protocol over Secure Socket Layer 或 Hypertext TransferProtocol Secure&#xff0c;超文本传输安全协议&#xff09;&#xff0c;是以…

【Android】保留elevation层级效果,舍弃阴影效果

关于elevation属性 elevation是高度&#xff0c;海拔的意思 该属性可以设置View在父容器中的层级&#xff0c;即z属性 当view的elevation高于其它view时&#xff0c;它将显示在最上方&#xff0c;并产生阴影效果 关闭阴影效果 view的高度阴影&#xff0c;通过outlineProvi…

【电磁学】-超表面

目录 一、定义与特性 二、工作原理 三、应用领域 四、研究进展与挑战 五、总结 一、定义与特性 定义&#xff1a; 超表面&#xff08;metasurface&#xff09;是一种厚度远小于波长的人工层状材料&#xff0c;通常由周期性或准周期性的亚波长单元结构组成。这些单元结构能…

amis做工具库 - Evalutor的使用 (字符串变量解析)

const { isEffectiveApi, parse, Evaluator } amisRequire("amis"); // console.log(window.amisRequire); //amisRequire是sdk方式引入挂载到window到。里面还有一些window document赋值&#xff0c;需要在浏览器环境下执行。 node端执行会报错&#xff0c;只能np…

huggingface镜像站

huggingface下载太慢&#xff0c;大模型文件太大。用huggingface_hub镜像。 pip install -U huggingface_hub pip install huggingface-cli export HF_ENDPOINThttps://hf-mirror.com huggingface-cli download --resume-download shenzhi-wang/Llama3-8B-Chinese-Chat --loc…

每天写java到期末考试--实验一---创建类---6.29

2、定义一个类Calculate,其中有一个main方法。 3、在main方法中,首先调用Scanner类,从键盘输入一个整数放到变量count中,count表示将要从键盘读入 的整数个数,然后调用循环语句从键盘读入count个整数,并保存到数组value中。 (1)将这count个整数求和,然后求出平均值。最后输出…

在Ubuntu 18.04.6 LTS 交叉编译生成Windows 11下的gdb 8.1.1

1. 安装mingw sudo apt-get install mingw-w64 2. 下载 gdb 8.1.1源码 https://ftp.gnu.org/gnu/gdb/gdb-8.1.1.tar.gz 解压命令 tar -xf gdb-8.1.1.tar.gz 进入目录,创建build目录: hq@hq:~/gdb-8.1.1/build$ 执行配置 ../confi

java实现图片添加水印

文章目录 前言一、工具类WatermarkUtil二、工具类介绍2.1 图片来源类型2.2 水印类型2.3 读取本地图片2.4 读取网络图片2.5 水印处理2.6 添加水印 三、测试添加水印总结 前言 给图片添加水印是一个很常见的需求&#xff0c;一般是用来防盗用。比如我们csdn上面写的文章中&#…

【鸿蒙学习笔记】@Extend装饰器:定义扩展组件样式

官方文档&#xff1a;Extend装饰器&#xff1a;定义扩展组件样式 [Q&A] Extend装饰器 作用 Extend用于扩展原生组件样式。 [Q&A] Extend装饰器 特点 &#xff11;・Extend仅支持在全局定义&#xff0c;不支持在组件内部定义。 &#xff12;・Extend支持封装指定组件的…

左耳听风_018_17_故障处理最佳实践应对故障

你好&#xff0c;我是陈浩网名猪耳朵house.我们多多少少呢都会经历一些线上的故障。 在我自己的职业生涯中呢就经历过很多的线上故障。 说实话&#xff0c;线上故障是我们技术人员成长中必须要经历的事儿。 从故障中呢&#xff0c;我们可以吸取到很多的教训&#xff0c;也能…

【Vue】单向和双向数据绑定

在 Vue.js 中&#xff0c;数据绑定可以分为单向数据绑定和双向数据绑定两种类型。 单向数据绑定 单向数据绑定是指数据从模型流向视图&#xff0c;即数据的变化会自动反映到视图中&#xff0c;但视图中的变化不会自动反映回模型。Vue.js 中的单向数据绑定主要通过以下方式实现…

Linux的fwrite函数

函数原型: 向文件fp中写入writeBuff里面的内容 int fwrite(void*buffer&#xff0c;intsize&#xff0c;intcount&#xff0c;FILE*fp) /* * description : 对已打开的流进行写入数据块 * param ‐ ptr &#xff1a;指向 数据块的指针 * param ‐ size &#xff1a;指定…

无人机赋能工程测绘

勘察设计 业务挑战 采集效率低导致工程周期延长&#xff0c;难以满足及时交付的需求 外业工作量大&#xff0c;人员、时间、设备投入成本高 测绘成果单一&#xff0c;仅限于数字线划图&#xff0c;无法提供可视化模型 无人机优势 快速构建二三维模型&#xff0c;提供丰富…

VUE-CLI脚手架项目的初步创建与配置

目录 1&#xff0c;首先创建一个VUE项目&#xff0c;注意选择版本为 2.6.10 2&#xff0c;打开APP.vue文件&#xff0c;并且删除APP.vue中多余的代码 3&#xff0c;创建index.vue文件 4&#xff0c;在此文件中写入如下图片中的代码来初步创建页面 5&#xff0c;创建router…

前端代码生成辅助工具

1&#xff0c;Axure Axure设计的界面如何生成HTML文件 https://blog.csdn.net/qq_43279782/article/details/112387511 Axure 生成HTML 文件&#xff0c;并用Chrome打开 https://blog.csdn.net/qq_30718137/article/details/80621025 2&#xff0c;OpenUI [开源] OpenUI …

树上启发式合并(DSU-on-Tree)

树上启发式合并DSU-on-Tree 前言入门题例1例2例3CF600ECF570D 略复杂一点的题目CF208ENC235719NC235715 小结 前言 树上启发式合并&#xff0c;用来解决子树查询问题&#xff0c;是一种离线的、“暴力的”算法。从某种角度而言&#xff0c;与莫队算法有些类似&#xff0c;即&a…