当前位置: 首页 > news >正文

《effective c++》学习笔记

从今天开始看《effective c++》这本书,把学到的东西当做笔记记下来,算是督促自己学习吧,也算是和大家一起分享一点东西,理解不当的地方,请谅解。(每天更新三个条款)。

一:让自己习惯C++

  条款1:视C++为一个语言联邦
  条款2:尽量以const,enum,inline替换#define
  条款3:尽可能使用const
  条款4:确定对象被使用前已先被初始化

二:构造/析构/赋值运算

  条款5:了解C++默默编写并调用哪些函数
  条款6:若不想使用编译器自动生成的函数,就该明确拒绝
  条款7:为多态基类声明virtual析构函数
  条款8:别让异常逃离析构函数
  条款9:绝不在构造和析构过程中调用virtual函数
  条款10:令operator=返回一个reference to *this
  条款11:在operator=中处理“自我赋值”
  条款12:复制对象时勿忘其每一个成分

条款1:视C++为一个语言联邦

主要内容:

  1、这个条款主要说把C++看做多个次语言的联邦,包含C,object-Oriented C++,Template C++,STL。视情况而定用哪一部分。

  ps:可能就像我写C++就是套着类的框,写面向过程编程代码~

条款2:尽量以const,enum,inline替换#define

主要内容:

  1、宏定义的常量通常在预处理时期就被替换了,所以如果报错的话,可能很难追踪到错误点,用const常量定义会比较好.

  2、const替换宏定义有两点需要注意:
  (1)定义常量指针的时候,需要指针和指针所指内容都是const,所以用const string比较好。
  (2)想要为某个类定义一个专属的常量,这时候用宏定义就不太行了,因为宏定义了之后,整个文件后面都可以用,除非#define #undefine限制?这时候用const常量比较好。

  3、假如定义一个const常量作为类的专属常量,这时候类里面有个数组,需要const常量作为其下标,有的编译器可能没办法直接声明const常量的时候定义给于初值,必须在类外去定义初始化。这时候就可以用enum代替const常量。

  4、宏也可用来定义函数,它没有函数调用的额外开销,直接是在预处理期间被替换了,但是宏函数也有副作用,这时候用inline去替换宏函数比较好。

条款3:尽可能使用const

主要内容:

  1、const可以作用于对象,以及函数各个部分,能用const的地方尽量用const,防止不小心导致的错误更改。

  2、const修饰成员函数,成员函数可以进行重载为const和非const成员函数。
  调用关系:
  (1)const对象可以调用const成员函数,不可以调用非const成员函数,而非const对象可以调用const和非const成员函数。
   (2)const成员函数只能调用const成员函数,而非const成员函数可以调用非const成员函数和const成员函数。

  3、bitwise constness和logical constness。
  (1)bitwise constness认为只要成员函数是const修饰的,那么里面的任何bit都不能修改。不过,假如一个类里面有一个char*类型的指针,我们不能修改指针,但是我们可以修改指针所指物。
  (2)logical constness认为成员函数是const修饰的,那么里面的某些bit是可以修改的。比如上述3-1例子,还比如我们有一个类,里面某些成员我们是可以通过mutable进行修饰,达到修改其的意图。

  4、const和non-const成员函数避免重复。
    成员函数有const和非const,如果里面做的事情一样,会造成代码冗余,解决方法就是通过非const成员函数调用const成员函数,类似于这样:const_cast<char&>(static_cast<const T&>(*this)[pos]);也就是说先将对象转为const类型调用const成员函数,因为非const成员函数要返回是非const的结果,所以用const_cast去除const成员函数返回的结果的const属性。

条款4:确定对象被使用前已先被初始化

主要内容:

  1、不管是内置类型还是自定义类型的对象,都应该在使用之前进行初始化,防止出现意想不到的错误(除非你明确其在用之前一定会被赋值)。

  2、尽量使用成员初始化列表去初始化类的成员,一方面是效率会高(省了无畏的赋值),另一个方面是类的某些成员只能通过初始化去完成,比如const类型,引用类型。

  3、成员初始化列表初始化成员变量的顺序取决于声明成员变量的次序。

  4、非局部的static对象(全局的,namespace作用域的或者class内或file作用域内的static对象)在多个文件里面使用时,它在使用之前是否已初始化是不确定的,解决方法是将其搬到自己的专属函数内,然后返回其引用即可,转化为局部的static对象。

  5、多线程情况下可能会有竞争,4这个方法不能适用,除非是多线程启动之前,单线程去一一调用函数完成初始化。

条款5:了解C++默默编写并调用哪些函数

主要内容:

  1、一个空的class,编译器默认会生成默认的构造函数,析构函数,拷贝构造,赋值构造函数。生成默认构造和析构函数,作用是调用父类或者非static成员变量的构造和析构函数。如果自己声明了自定义的构造和析构,那么编译器将不会默认生成。拷贝构造,赋值构造函数是浅拷贝,如果类内管理资源,析构的时候可能会有问题,需要重载拷贝构造,赋值构造函数。编译器有时也会拒绝生成默认的拷贝构造,赋值构造函数,比如类内有const成员或者引用类型成员,如果想要为引用类型成员赋值,就得自己重载拷贝构造,赋值构造函数。

  2、父类的拷贝构造函数如果是private的,那么子类也不会生成一个默认的拷贝构造函数,因为没有权限。

条款6:若不想使用编译器自动生成的函数,就该明确拒绝

主要内容:

  1、如果不想让类支持拷贝或者赋值,那么可以声明拷贝构造,赋值构造函数两个函数为private,这样做就不会被拷贝或者赋值了,也不用定义出来其实现,防止类内的其他成员函数或者友元函数调用。

条款7:为多态基类声明virtual析构函数

主要内容:

  1、类定义出来如果是作为其他类的基类,那么就要给它的析构函数定义为virtual析构函数,防止在释放基类指针指向派生类对象的时候发生内存泄漏。

  2、如果类不打算作为其他类的基类,那么就不要把析构函数定义为virtual析构函数,否则对象的体积将会增加,且因含有虚表指针,就不具有移植性了。这是因为实现virtual函数的原理是对象内部包含了一个虚表指针,基类派生类的虚函数的指针都存放在数组里面,对象调用哪个虚函数,是由虚表指针去函数指针数组里面找到然后调用。每个对象都含有一个虚表指针,一个指针在32位机器上占4个字节,在64位机器上占8个字节。

  3、如果类没有将析构函数定义为virtual析构函数,那么最好不要继承它。

条款8:别让异常逃离析构函数

主要内容:

  1、析构函数中有异常的话,如果此时是vector类型,那么可能第一个对象就销毁时就抛异常,继续调用其他对象析构,第二个对象抛出异常,此时系统将会出现不明确的行为或者过早结束,所以不要在析构的时候抛异常。

  2、较好的方法是将可能抛出异常的函数开放给用户,让用户去调用,此时用户就会决定异常抛出后的一个反应,程序员在析构时可以加一个双层保险,如果没有调用函数标记,那么析构这里可以调用一次,捕获异常并且记录或者结束程序。

条款9:绝不在构造和析构过程中调用virtual函数

主要内容:

  1、不要在析构或者构造过程中调用virtual函数。假设现在有一个基类A,里面有一个A构造函数,logTransaction虚函数,A构造函数内部调用logTransaction虚函数,此时B和C继承自A类,B和C类重写了自己的logTransaction函数。如果此时定义一个B类,B的构造函数会被调用,但是首先应该先构造B的基类A,这时候A去构造函数过程中调用A类的虚函数logTransaction(基类构造期间,虚函数还不是虚函数),这个现象的原因是此时B类还没有构造好,它里面的成员对象都是未初始化的,编译器会当做B类还不存在。这种代码一般编译器会有警告。

  2、还有一种情况,当基类构造函数调用普通的init函数,然后init函数里面调用了虚函数,那么此时编译器就有可能就不会有任何告警,但是程序执行现象就不会如我们期望的一般。

  3、解决方法是基类logTransaction函数不要定义为虚函数,将其定义为普通函数,然后通过构造函数去调用,接受参数,这时候,派生类在构造的时候将自己这边的参数传到基类的构造函数那边,完成调用。也就是说我们无法使用虚函数从基类向下调用,在构造期间,我们可以让派生类将必要的构造信息向上传递给基类构造函数。

条款10:令operator=返回一个reference to *this

主要内容:

  1、按照内置类型可以连续赋值的形式,我们在写operator=函数的时候,就必须返回返回*this引用,+=也是如此。否则返回值效率也会降低。

条款11:在operator=中处理“自我赋值”

主要内容:

  1、在写operator=的时候,需要处理自我赋值的情况,提高效率,还有一点是需要注意在抛出异常的时候,原本对象已经被破坏的情况,正常来说,应该是先申请临时对象,再进行复制,将原对象释放掉,让指针重新指向新的临时对象,返回*this。

  2、如果追求效率, 可以先把要复制的对象拷贝一份,然后用swap函数交换当前对象和拷贝的临时对象。

条款12:复制对象时勿忘其每一个成分

主要内容:

  1、拷贝构造函数和赋值函数中必须处理每一个成员变量,即使是后面新加了一个变量,也要在拷贝构造函数和赋值函数中进行处理。否则会有问题。

  2、派生类进行拷贝构造函数和赋值函数的时候,也需要通过派生类的拷贝构造去调用基类的拷贝构造,不能忘记了。

  3、不要妄想用拷贝构造函数调用赋值函数,或者赋值函数调用拷贝构造函数。如果真的要消除两者之间重复的代码,可以将重复的代码提取出来为一个init函数,放在private里,让拷贝构造函数和赋值函数调用init函数即可。

相关文章:

《effective c++》学习笔记

从今天开始看《effective c》这本书&#xff0c;把学到的东西当做笔记记下来&#xff0c;算是督促自己学习吧&#xff0c;也算是和大家一起分享一点东西&#xff0c;理解不当的地方&#xff0c;请谅解。&#xff08;每天更新三个条款&#xff09;。 一&#xff1a;让自己习惯C…...

11.盛水最多的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;你不能倾斜容器。 示例 1&a…...

通过在idea上搭建虚拟hadoop环境使用MapReduce做词频去重

idea上的MapReduce ​ 一般在开发中&#xff0c;若是等到环境搭配好了再进行测试或者统计数据&#xff0c;数据处理等操作&#xff0c;那会很耽误时间&#xff0c;所以一般都是2头跑&#xff0c;1波人去在客户机上搭建环境&#xff0c;1波人通过在idea上搭建虚拟hadoop环境&am…...

AI技术变革与企业服务创新

1、AI的技术变革 1&#xff09;AI市场规模 2&#xff09;AI大模型发展历程 3&#xff09;AIGC发展背景 4&#xff09;AIGC技术能力 AIGC的技术架构逻辑上分为基础层、技术层、能力层、应用层、终端层五大板块&#xff0c;其中核心技术层涵盖AI技术群和大模型的融合创新&#…...

探秘Facebook:社交媒体的未来之路

Facebook&#xff0c;作为全球最大的社交媒体平台之一&#xff0c;一直处于数字社交革命的前沿。然而&#xff0c;随着科技和社会的不断发展&#xff0c;Facebook正面临着新的挑战和机遇。本文将探索Facebook的未来之路&#xff0c;揭示社交媒体的新趋势和发展方向。 1. 深度社…...

rust的类型转换和一些智能指针用法(四)

基础类型 使用 as 关键字&#xff1a;用于基本数值类型之间的转换&#xff0c;例如将 i32 转换为 u32。 例子&#xff1a;let x: i32 10; let y: u64 x as u64; 使用标准库中的转换方法&#xff1a;如 from() 和 into() 方法&#xff0c;这些方法通常用于无风险的转换&#…...

探索大模型技术及其前沿应用——TextIn文档解析技术

前言 中国图象图形大会&#xff08;CCIG 2024&#xff09;于近期在西安召开&#xff0c;此次大会将面向开放创新、交叉融合的发展趋势&#xff0c;为图像图形相关领域的专家学者和产业界同仁&#xff0c;搭建一个展示创新成果、展望未来发展&#xff0c;集高度、深度、广度三位…...

Java HashMap 扩容机制深度解析

HashMap 的一个关键性能优化就是扩容机制&#xff0c;即在哈希表达到一定负载因子时&#xff0c;自动进行扩容&#xff0c;以保持检索效率。 在这篇文章中&#xff0c;我们将深入研究 HashMap 的扩容机制&#xff0c;了解其原理和影响因素。 1. 初始容量和负载因子 在深入了解…...

一、Electron 环境初步搭建

新建一个文件夹&#xff0c;然后进行 npm init -y 进行初始化&#xff0c;然后我们在进行 npm i electron --save-dev , 此时我们按照官网的教程进行一个初步的搭建&#xff0c; 1.在 package.json 文件进行修改 {"name": "electron-ui","version…...

ffmpeg编码器编码元数据的过程以及编码前后的差异

编码方式为avcodec_send_frame&#xff1a;将原始帧发送到编码器进行编码 编码过程完成于avcodec_receive_packet&#xff1a;从编码器接收编码后的压缩数据&#xff0c;也就是说已经编码压缩完成了&#xff0c;并存储到avpacket中&#xff0c;此时元数据被分割成多个NALU单元&…...

AB测试学习(附有相关代码)

目录 一、基本概念1. 定义2. 作用3. 原理 二、实验基本原则三、实验步骤四、实验步骤详解1. 确定实验目的2. 确定实验变量3. 实验指标设计3.1 实验指标类型&#xff08;按作用区分&#xff09;3.1.1 核心指标3.1.2 驱动指标&#xff08;跟踪指标&#xff09;3.1.3 护栏指标 3.2…...

用idea将java文件打成jar包

一、用idea将java文件打成jar包 1、在idea上选择file—Project Structure 2、Artifacts —点–JAR—From modules with dependencies 3、选择要打包的java文件 4、Build — Build Artifacts 5、找到刚才添加的Artifacts直接Build 6、生成jar包文件...

Ansible——group模块

目录 参数总结 语法示例 创建用户组 删除用户组 设置组的 GID 创建系统组 修改组的 GID 添加用户组并附加其他组属性 删除指定 GID 的用户组 帮助信息 Playbook示例 基本示例 1. 创建用户组 2. 删除用户组 进阶示例 1. 修改组的 GID 2. 综合管理多个用户组 3…...

Sql注入-报错注入

报错注入&#xff08;Error-Based Injection&#xff09;是一种通过引起数据库报错并从错误信息中提取有用信息的SQL注入攻击手法&#xff1b;攻击者利用数据库在处理异常情况时返回的错误消息&#xff0c;来推断出数据库结构、字段名甚至数据内容&#xff1b;这种攻击方法依赖…...

pyqt 回车触发两次editingFinished的解决办法

在英文Qt论坛看到的解决办法 def editingFinished_triger(self):#self.sender() is the QlineEditif not self.sender().isModified(): returnself.sender().setModified(False)#treat code ...#treat code ...下面是一个错误使用editingFinished的例子 在上面界面中有一个文本…...

爬取股票数据python

最近在搜集数据要做分析&#xff0c;一般的数据来源是一手数据&#xff08;生产的&#xff09;和二手数据&#xff08;来自其他地方的&#xff09;。 今天我们爬取同花顺这个网站的数据。url为&#xff1a;https://data.10jqka.com.cn/ipo/xgsgyzq/ 话不多说直接上代码。有帮…...

每日新闻掌握【2024年6月4日 星期二】

2024年6月4日 星期二 农历四月廿八 TOP大新闻 张雪峰近2万元志愿填报服务已售罄 2024年高考临近&#xff0c;考生紧张的是考场上能否如常发挥&#xff0c;而考场之下&#xff0c;家长们已经开始为孩子的志愿填报焦心。峰学蔚来是由张雪峰打造专门提供高考志愿填报服务的APP&am…...

智谱AI 发布最新开源模型GLM-4-9B,通用能力超Llama-3-8B,多模态版本比肩GPT-4V

自 2023 年 3 月 14 日开源 ChatGLM-6B 以来&#xff0c;GLM 系列模型受到广泛关注和认可。特别是 ChatGLM3-6B 开源以后&#xff0c;开发者对智谱AI 第四代模型的开源充满期待。 为了使小模型&#xff08;10B 以下&#xff09;具备更加强大的能力&#xff0c;GLM 技术团队进行…...

从写简历到谈薪资的最全教程

从写简历到谈薪资的最全教程 目录简历注意事项举个例子写简历投递简历也有技巧模拟面试的重要性面试经验怎么刷不断迭代达越来越强斗智斗勇谈薪资拿到offer就结束了吗&#xff1f;我能给你的帮助 目录 大家好&#xff0c;我是一名普通本科毕业的学生&#xff0c;工作数年&#…...

Vue3 响应式API:高级函数(二)

shallowRef() shallowRef 是一个特殊的 ref 创建函数&#xff0c;它允许你创建一个只追踪顶层属性变化的响应式引用。与 ref 不同的是&#xff0c;shallowRef 创建的响应式引用对其内部值的深层嵌套属性是不敏感的&#xff0c;也就是说&#xff0c;只有当 shallowRef 的 .valu…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径&#xff0c; 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解&#xff0c;但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后&#xff0c;通常在该文件中会出现以下配置&…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...