《effective c++》笔记

2023-11-16

1、“object” 在“object oriented技术中的真正意义是“物件,物体” 而非 “对象、目标”

导读

1、术语

1)声明式
告诉编译器名称和类型,但略去细节

  • std::size_t numDigit (int number);

// std命名空间 包含几乎所有c++标准程序库元素,C89标准程序库也适用于c++, 继承自C的符号(eg. size_t)有可能存在于global 作用域或 std内,或都有,取决于哪个头文件被#include

// size_t 只是一个typedef, 是c++ 计算个数时用的不带正负号(unsigned)类型,也是vector, deque, string内的operator[ ] 函数接收的参数类型。

2)定义式 definition
提供编译器一些声明式所遗漏的细节,对对象来说,定义式是编译器为此对象分配内存的地点,对function, function template而言,定义式提供了代码本体;对class, class template而言,定义式列出了成员
3) 初始化 initialization

  • default构造函数可被调用但不带任何实参,要么没参数,要么每个参数有缺省值
  • explicit :阻止函数被用来执行隐式类型转换,但仍可显式转换

4)copy构造函数:以同型对象初始化自我对象 --> 定义一个对象pass by value
copy assignment操作符:从另一个同型对象中拷贝其值到自我对象
区分:新对象被定义,一定会调构造函数 eg. Widgt w3 = w2;

在这里插入图片描述
2、命名习惯
1)两个参数名称

  • lhs: left-hand-side 左手端
  • rhs: right-hand-side 右手端
    对于成员函数,左侧实参由this指针表现出来,eg. 见上一幅图,所以单独使用参数名rhs

3、TR1和Boost

一、让自己习惯C++

条款01:视c++为一个语言联邦

  • C: pass-by-value更高效
  • Objected-Oriented C++: 由于用户自定义的构造函数和析构函数的存在,pass-by-reference-to-const更好
  • Template C++: 泛型编程
  • STL: template程序库:容器、迭代器、算法、函数对象,迭代器&函数对象都是在c指针之上塑造出来的,所以pass-by-value守则适用。

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

1、宁可以编译器替换预处理器
在这里插入片描述
// 该名称会被预处理器移走,编译错误或debug时追踪不到该记号
 作为语言常量,会被编译器看到,也会进入记号表
// 作为语言常量,会被编译器看到,也会进入记号表

2、宏看起来像函数,但不会招致函数调用带来的额外开销,不要用#define实现形似函数的宏===>使用template inline函数

3、对于单纯常量,最好改用 inline函数替换 #defines

条款03:尽可能使用const

const出现在星号左边,表示物是常量;出现在星号右边,表示指针自身是常量
const

  • mutable关键字,使成员变量即使在const成员函数内也能被修改
  • 若函数返回类型是个内置类型,改动函数返回值从来就不合法,即使合法,c++以by value返回对象改动的其实是副本,不是本身。
  • const 成员函数承诺绝不改变其对象的逻辑状态
  • 在const和 non-const 成员函数中避免重复: non-const 成员函数调用 const 成员函数
    在这里插入图片描述

const_cast :从const operator[ ]的返回值中移除const

条款04:对象使用前初始化

  • 确保每一个构造函数都将对象的每一个成员初始化

  • 区分赋值(assignment)和初始化:
    对象的成员变量的初始化动作发生在进入构造函数本体之前, default构造函数被自动调用之时—> 使用初始化列表(member initialization list)
    在这里插入图片描述

  • 总是在初值列中列出所有成员变量

  • 总是使用成员初值列(最好做法),即使内置类型初始化和赋值成本相同

  • 成员变量是const 或 references 就一定需要初值,不能被赋值

  • 成员初始化次序:base classes—derived classes, 而class的成员变量按声明次序初始化

  • 跨编译单元的初始化次序问题:以local static对象替换non-local static
    ========
    static对象:寿命从被构造到程序结束,main()结束时析构函数自动调用,销毁对象
    local static对象: 只包括函数内的static对象
    non-local static对象:global、namespace内、classes内、file作用域内被声明为static的对象

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

条款05:c++默默编写调用了哪些函数

在这里插入图片描述

  • c++不允许让reference改指向不同对象
  • 若想在一个内含reference 、const 成员的class内支持赋值操作,必须自己定义copy assignment操作符

条款06:明确拒绝不想使用的编译器自动生成的函数

  • 将相应的函数声明为private 并且不予实现。或使用一个专门的 base class
    在这里插入图片描述

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

  • 带多态性质的base classes应该声明一个virtual 析构函数。

  • 若class 带有任何virtual 函数,就应该拥有一个virtual析构函数。

  • 其余情况classes 不该声明
    在这里插入图片描述

  • 只想在程序中使用时间,不想操心时间如何计算等细节,可设计一个工厂函数,返回指针指向一个计时对象 ——> 返回一个base class指针,指向新生成之derived class 对象
    在这里插入图片描述

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

  • 析构函数绝对不要吐出异常,否则可能“过早结束程序” 或 “发生不明确行为”, 若一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下他们(不传播)或结束程序std::abort
try {}  catch { 制作运转记录,记下对close 的调用失败 }
  • 若客户需要对某个操作函数运行期间抛出的异常做出反应,那么class 应该提供一个普通函数(而不是在析构函数中)执行该操作

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

原因:

  • 基类构造函数的执行早于继承类。当 base class构造函数执行时,derived class的成员变量尚未初始化,若基类构造函数中有一个纯虚函数,则创建子类对象时先被调用的是父类的版本,而不是子类的重新实现版本。
  • base class构造期间virtual函数绝不会下降到derived class阶层---------即,在base class 构造期间,virtual函数不是virtual 函数

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

eg. int x= y = z = 5; 为实现连锁赋值,赋值操作符返回类型是个reference,指向当前对象(操作符的左侧实参)

class Widget{
public:
...
	Widget& operator=(const Widget& rhs)
	{
	...
	return* this; //返回左侧对象
	}
...
};

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

  • 别名:有一个以上的方法指称某对象,事实上,两个对象只要来自同一个继承体系,甚至不需声明为相同类型就可能造成 “别名”,因为基类的指针或reference可以指向一个继承类对象

  • 自我赋值安全
    在这里插入图片描述

  • 异常安全性

  • 确定任何函数操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然是正确的。

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

  • copying函数确保:
  1. 复制对象内所有成员变量
  2. 调用所有base class内的适当的copying函数
    在这里插入图片描述
  • 若copy构造函数和copy assignment操作符有相近的代码—>建一个新的成员函数给两者调用(通常是private,且常被命名为 init),不能用某个copying函数实现另一个copying函数

三、资源管理

条款13:以对象管理资源

  1. 为防止资源泄露,使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源
class Investment {...};
Investment* createInvestment(); /工厂函数,供应Investment对象
/返回指针,指向Investment继承体系内的动态分配对象,调用者有责任删除它

  • (漏截的图)许多资源被动态分配于heap内而后被用于单一区块或函数内,它们应该在控制…
    在这里插入图片描述
  1. 两个常被使用的RAII class是:
    auto_ptr: 受其管理的资源不能有一个以上的auto_ptr同时指向它(不然对象会被删除一次以上)--------若被复制,会变成null, 而复制所得的指针将取得资源唯一拥有权
    tr1::shared_ptr:引用计数型智能指针,追踪共有多少对象指向某笔资源,在无人指向时自动删除该资源------复制行为正常
    在这里插入图片描述

条款14:在资源管理类中小心copying行为

1)并非所有的资源都是基于堆,当需要建立自己的资源管理类时,RAII对象被复制时常见的两种行为:

  1. 禁止复制

在这里插入图片描述

  1. 使用引用计数法:保有资源直到最后一个使用者被销毁

2)复制RAII对象必须一并复制它所管理的资源(深度拷贝:包含指针和指针所所指的内存),所以资源的copying行为决定RAII对象的copying行为

条款15:在资源管理类中提供对原始资源的访问

1、RAII classes并不是为了封装某物而存在,而是为了确保一个特殊行为——资源释放——会发生

2、很多APIs需绕过你写的资源管理类,直接访问资源,所以每一个RAII class应该提供一个“取得其所管理之资源”的办法

3、对原始资源的访问可能经由显式或隐式转换,一般而言显示转换比较安全,但隐式转换对客户比较方便 (*书上例子没有很看懂)

条款16/ 17:使用new 和delete

1、使用new 和delete采用相同形式,确保被删内存中有多少对象,就有多少个析构函数被调用。——单一对象 or 对象数组
在这里插入图片描述
delete [ ]: 读取若干内存并将它解释为内存大小,然后开始多次调用析构函数

2、以独立语句将newed对象置入智能指针
函数调用时,在编译器产出一个调用码之前,必须首先核算即将被传递的各个实参,该核算次序是不确定的(看编译器认为哪样更高效),如下可能导致资源泄露
在这里插入图片描述
因为若调用priority②异常,先执行的“new widget" ①返回的指针将会遗失,未被置入tr1::shared_ptr内

解决办法: 使用分离语句,分别写出 1)创建widget 2)置入智能指针内 3)再把指针传给函数processWidget
在这里插入图片描述

四、设计与声明

条款18、让接口容易被正确使用,不易被误用

1、接口的一致性,与内置类型的行为兼容
2、阻止误用:建立新类型、限制类型上的操作、束缚对象值,消除客户的资源管理责任

  • tr1::shared_ptr支持定制型删除器,记录引用次数(多线程程序修改)变为0时调用其诞生所在那个DLL的delete

条款19、设计class犹如设计type

  • 新对象该如何被创建和销毁:构造、析构、内存分配函数和释放函数
  • 对象的初始化和赋值差别:构造函数、赋值操作符
  • 新type的对象被pass by value意味着什么:copy构造函数
  • 新type的“合法值”:成员变量通常只有某些数据集有效
  • 新type需要什么样的转换:允许T1隐式转为T2就必须在T1内写一个类型转换函数(operator T2)或在class T2内写一个non-explicit-one-argument(可被单一实参调用)的构造函数

条款20、以pass-by-reference-to-const替换pass-by-value

前者通常比较高效,并可避免切割问题(slicing problem)
在这里插入图片描述

  • reference往往以指针实现出来,若对象 属于内置类型以及STL的迭代器和函数对象,pass-by-value比较适当

条款21、必须返回对象时,别妄想返回其reference

在这里插入图片描述
在这里插入图片描述

  • local对象在函数退出前被销毁,指向该对象导致无定义行为
  • 指向local static时,由于返回的是reference,因此调用端看到的永远是static rational对象的“现值”,即使两次参数不同的调用改变了static rational对象值,结果也相等。(不是很懂,明明值变了)

条款22、将成员变量声明为private

  • 从封装的角度看,只有两种访问权限:private提供封装 和 其他(不提供封装)
  • public成员变量被取消,所有使用它的客户码都会被破坏
  • protected成员变量被取消,所有使用它的derived classs都会被破坏,并不比public更具封装性

条款23、以non-member, non-friend替换member函数

增加封装性、包裹弹性、较低的编译相依度、增加可扩展性

  • 被封装的东西即不再可见,越多东西被封装。越少人可以看到,就有越大的弹性去改变它,改变仅影响直接看到改变的那些人事物
  • 考虑对象内的数据,越少代码看到数据(访问),越多的数据可被封装,就越能自由改变对象数据,如成员变量类型、数量等
  • 让该类的non-member函数位于同一个namespace下,namespace可跨越多个源码文件,一个class的non-member可以是另一个class的member,不影响private成员封装性
  • 将不同的机能放在不同的头文件,但是在同一个namespace下,客户可轻松扩展这一组机能函数

条款24、若所有参数皆需要类型转换,采用non-member函数

若需要为某个函数的所有参数(包括被this指针所指的那个隐喻参数)进行类型转换,则该函数必须为non-member----允许编译器在每一个实参身上执行隐式类型转换

  • 只有当参数被列于参数列(parameter list内),这个参数才是隐式类型转换的合格参与者
  • explicit构造函数: 禁止隐式转换
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

《effective c++》笔记 的相关文章

随机推荐

  • 堆和栈的通俗解释【转】

    数据结构的栈和堆 首先在数据结构上要知道堆栈 尽管我们这么称呼它 但实际上堆栈是两种数据结构 堆和栈 堆和栈都是一种数据项按序排列的数据结构 栈就像装数据的桶或箱子 我们先从大家比较熟悉的栈说起吧 它是一种具有后进先出性质的数据结构 也就是
  • 医院RFID药物跟踪管理解决方案

    1 技术背景 基于 2018年2月6日 药物调配商QuVa Pharma 与Kit Check合作 为其医院药房客户 提供基于RFID药物跟踪管理解决方案 QuVa提供的系统包括Kit Check的 无源 超高频 UHF RFID 标签 该
  • WEB基础-变形动画

    字体图标 IconFont 图标字体也叫字体图标 就是字体做的图标 可以通过设置字体的方式改变图标的样式 受到近些年 扁平化设计 的影响 越来越多的图标都开始使用 IconFont 下载字体图标 首先打开IconFont 阿里巴巴矢量图标库
  • websocket详解

    之前利用websocket以及jQuery做了一个聊天通讯应用 最近在总结整个过程中的一些问题 也借此机会聊聊websocket协议 webSocket本身不存在跨域问题 所以可以利用webSocket来进行非同源之间的通信 webSock
  • pytorch打印模型梯度

    简介 有时候在调试模型训练过程时 我们需要打印模型中参数的梯度 去查看是否存在梯度消失或者梯度爆炸的问题 可以通过在backward之后查看params的grad属性来确认 参考代码如下所示 import torch 定义模型 class
  • Python3 面向对象编程

    好记性不如烂笔头 对之前阅读书籍进行梳理与总结 此文为 Python3面向对象编程 阅读笔记 文章目录 第一章 面向对象设计 第二章 Python对象 第三章 对象相似时 第四章 异常捕获 第五章 何时使用面向对象编程 第六章 Python
  • C# 导出 Excel 方法

    第一种 使用 Microsoft Office Interop Excel dll public void ExportExcel DataTable dt if dt null Microsoft Office Interop Excel
  • 关键词生成器在线-在线免费关键词生成器

    关键词生成 什么是关键词生成 关键词生成就是根据你输入的一个关键词生成成千上百的核心关键词 围绕着你输入的核心词来生成的 优先生成大量用户搜索的关键词 今天就给大家分享一款免费关键词生成工具 关键词生成的来源主要是用户都在搜索的词 相关搜索
  • CentOS-8-x86_64-1905安装

    CentOS 8 x86 64 1905安装 安装前准备 VMware Workstation 点击下载虚拟机软件 VMware Workstation是一款功能强大的桌面虚拟计算机软件 提供用户可在单一的桌面上同时运行不同的操作系统 和进
  • Crazy Thairs【树状数组+高精度+DP思想】

    题目链接 POJ 3378 题意 有N个点 问的是要求组成一个长度为5的上升子序列的组成有多少种 最搞事情的是这道题不用取模 所以 是一定会爆long long的 首先 很容易想到一点就是我们可以开一个dp maxN 5 表示的是 dp i
  • Vagrant学习笔记:搭建K8s集群

    通常情况下 我们在使用VMware VirtualBox这一类虚拟机软件创建虚拟开发环境时 往往需要经历寻找并下载操作系统的安装镜像文件 然后根据该镜像文件启动的安装向导一步一步地安装与配置操作系统 最后还需要从零开始安装开发与运维工具 整
  • 计算机考研复试机试怎么速成,西安电子大学计算机考研复试机试(2019)+ 学长讲解(6)+ 作业...

    学长讲的就是算法笔记的入门算法 作业1 链接 https www nowcoder com questionTerminal 0f64518fea254c0187ccf0ea05019672 来源 牛客网 有一个网络日志 记录了网络中计算任
  • Java各种集合判空总结

    目录 集合判空 CollectionUtils isEmpty推荐 原始判断 isEmpty 其他 数组判空 集合判空 CollectionUtils isEmpty推荐 这个使用到了spring的工具类 需要提前引入依赖 import o
  • 机器学习2018-12-28

    机器学习 组成 主要任务 分类 classification 将实例数据划分到合适的类别中 应用实例 判断网站是否被黑客入侵 二分类 手写数字的自动识别 多分类 回归 regression 主要用于预测数值型数据 应用实例 股价价格波动的预
  • 用编程器免拆夹子刷斐讯K2 K2P解决难搞固件 刷BREED 无损原EEPROM

    文章中放的几个地址都是思路来源 感谢各路大神原帖子的思路 因为我刷机时候没有拍照 只好借用各位大佬的图来说明步骤 我做一下整理会放出本篇刷机流程 很简单 K2 22 6 532 231软件版本已经无解 UBOOT等可以软刷的方式都被堵死 编
  • .NET编程——利用C#实现TCP协议的异步通信Socket套接字(WinForm)

    本文将介绍利用基于TCP通信协议的Socket实现服务器与客户端之间的数据传输 目录 前言 计算机通信 创建服务器 服务器通信 创建客户端 客户端通信 前言 TCP IP Transmission Control Protocol Inte
  • 【编码-校验码】奇偶校验码

    https zhuanlan zhihu com p 26509678 引自原文 1 定义 奇偶校验位 英语 Parity bit 或校验比特 check bit 是一个表示给定位数的二进制数中1的个数是奇数还是偶数的二进制数 奇偶校验位是
  • 炫酷的Android智能下拉刷新框架,值得一看

    1 Android智能下拉刷新框架 SmartRefreshLayout 支持所有的 View AbsListView RecyclerView WebView View 和多层嵌套的视图结构 支持自定义并且已经集成了很多炫酷的 Heade
  • BRDF详解

    光照模型主要分为三类 测量模型 经验模型和基于物理的分析模型 在计算机图形学中介绍的光照模型为经验模型中的Phong模型 也就是本人理解的 根据点距光源的位置 入射角度等信息计算的 反射强度 包括漫反射强度 镜面反射强度 但是Phong模型
  • 《effective c++》笔记

    序 1 object 在 object oriented技术中的真正意义是 物件 物体 而非 对象 目标 导读 1 术语 1 声明式 告诉编译器名称和类型 但略去细节 std size t numDigit int number std命名