《More Effective C++》学习

news2024/12/26 11:37:32

条款1:仔细区别 pointers 和 references

  1. 引用应该被初始化,指针可以不被初始化。
  2. 不存在指向空值的引用这个事实意味着使用引用的代码效率比使用指针的要高。因为在使用引用之前不需要测试它的合法性。
  3. 指针与引用的另一个重要的不同是指针可以被重新赋值以指向另一个不同的对象。但是
    引用则总是指向在初始化时被指定的对象,以后不能改变。
    std::string s1("Nancy");
	std::string s2("Clancy");
	std::string& rs = s1; // rs引用s1
	std::string* ps = &s1; // ps指向s1
	rs = s2; // rs仍旧引用s1,但是s1的值现在是"Clancy"
 

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

这四个操作符是:static_cast、const_cast、dynamic_cast、reinterpret_cast。

  • const_cast 最普通的用途就是转换掉对象的 const 属性
  • dynamic_cast,它被用于安全地沿着类的继承关系向下进行类型转换。这就是说,你能用 dynamic_cast 把指向基类的指针或引用转换成指向其派生类或其兄弟类的指针或引用,而且你能知道转换是否成功。失败的转换将返回空指针(当对指针进行类型转换时)或者抛出异常(当对引用进行类型转换时)。它不能被用于缺乏虚函数的类型上。
  • 如你想在没有继承关系的类型中进行转换,你可能想到 static_cast。
  • reinterpret_cast,使用这个操作符的类型转换,其 的 转 换 结 果 几 乎 都 是 执 行 期 定 义 ( implementation-defined )。 因此,使用reinterpret_casts 的代码很难移植。reinterpret_casts 的最普通的用途就是在函数指针类型之间进行转换。

double result = static_cast<double>(firstNumber)/secondNumber;

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

在对数组进行传参使用多态时,程序会crash; 因为数组在移位至下一数据时,步长是形参(基类)的size,而不是指针实际指向数据类型(派生类)的size,所以会数组会移位至一个非法的地址 。

#include <iostream>
using namespace std;
 
class Base
{
public:
  virtual void test()
  {
    cout<<"Base::test()"<<endl;
  }
  int a;
};
 
class Derived: public Base
{
public:
   void test()
  {
    cout<<"Derived::test()"<<endl;
  }
  int b, c;
};
 
void testArray(Base bArray[], int n)
{
  for(int i =0; i<n; i++)
    bArray[i].test();  //i = 1时,程序crash; 编译器原先已经假设数组中元素
//与Base对象的大小一致,但是现在数组中每一个对象大小却与Derived一致,
//派生类的长度比基类要长,数组将移动到一个非法位置。
}
 
int main()
{
  Base *p = new Derived[2];  
  testArray(p, 2);    
}

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

提供无意义的缺省构造函数也会影响类的工作效率。如果成员函数必须测试所有的部分是否都被正确地初始化,那么这些函数的调用者就得为此付出更多的时间。而且还得付出更多的代码,因为这使得可执行文件或库变得更大。它们也得在测试失败的地方放置代码来处理错误。如果一个类的构造函数能够确保所有的部分被正确初始化,所有这些弊病都能够避免。缺省构造函数一般不会提供这种保证,所以在它们可能使类变得没有意义时,尽量去避免使用它们。

class EquipmentPiece {
public:
	EquipmentPiece(int IDNumber) {}
	virtual ~EquipmentPiece() {}
	int a = 1;
	float b = 2.0;
};
 
   //避免无用的缺省构造函数
	int ID1 = 1, ID2 = 2;
	EquipmentPiece bestPieces3[] = { EquipmentPiece(ID1), EquipmentPiece(ID2) }; 
// 正确,提供了构造函数的参数
 
	// 利用指针数组来代替一个对象数组
	typedef EquipmentPiece* PEP; // PEP指针指向一个EquipmentPiece对象
	PEP* bestPieces5 = new PEP[10]; // 也正确
	// 在指针数组里的每一个指针被重新赋值,以指向一个不同的EquipmentPiece对象
	for (int i = 0; i < 10; ++i)
		bestPieces5[i] = new EquipmentPiece(ID1);
	for (int i = 0; i < 10; ++i)
		delete bestPieces5[i];
	delete bestPieces5;

利用指针数组代替一个对象数组这种方法有两个缺点:第一你必须删除数组里每个指针所指向的对象。如果忘了,就会发生内存泄漏。第二增加了内存分配量,因为正如你需要空间来容纳EquipmentPiece对象一样,你也需要空间来容纳指针.

解决办法:

	//分配足够的 raw memory,给一个预备容纳 10 个EquipmentPiece objects 的
    //数组使用
    void* rawMemory = operator new[](10 * sizeof(EquipmentPiece));
    
    //让 basePiece 指向此块内存,使这块内存被视为一个 EquipmentPiece 数组
	EquipmentPiece* bestPieces6 = static_cast<EquipmentPiece*>(rawMemory);
 
    //利用 “placement new”构造这块内存中的 EquipmentPiece objects
	for (int i = 0; i < 10; ++i)
		new(&bestPieces6[i]) EquipmentPiece(i);
 
    //将 basePieces 中的各个对象,以其构造顺序的相反顺序析构掉
	for (int i = 9; i >= 0; --i)
		bestPieces6[i].~EquipmentPiece(); 
       // 如果使用普通的数组删除方法,程序的运行将是不可预测的
       //因为 basePieces 并非来自 new operator
 
    //释放 raw memory
	operator delete[](rawMemory);

条款5:对定制的“类型转换函数”保持警觉

单自变量 constructors 是指能够以单一自变量成功调用的 constructors。如此的 constructor 可能声明拥有单一参数,也可能声明拥有多个参数,并且除了第一参数之外都有默认值。

class Name{
public:
 Name(const string& s);  //可以把string转换成Name
 ...
};

class Rational{
public:
 Rational(int numerator = 0,int denominator = 1);
 //可以把 int 转换成 Rational
 ...
};

有两种函数允许编译器进行这些的转换:单参数构造函数(single-argument constructors)和隐式类型转换运算符。

隐式类型转换运算符只是一个样子奇怪的成员函数:operator关键字,其后跟一个类型符号。你不用定义函数的返回类型,因为返回类型就是这个函数的名字。

class Rational {
public:
	Rational(int numerator = 0, int denominator = 1) // 转换int到有理数类
	{
		n = numerator;
		d = denominator;
	}
 
	operator double() const // 转换Rational类成double类型
	{
		return static_cast<double>(n) / d;
	}
 
	double asDouble() const
	{
		return static_cast<double>(n) / d;
	}
 
private:
	int n, d;
};
 
	//谨慎定义类型转换函数
	Rational r(1, 2); // r的值是1/2
	double d = 0.5 * r; // 转换r到double,然后做乘法
	fprintf(stdout, "value: %f\n", d);
	std::cout << r << std::endl; // 应该打印出"1/2",但事与愿违,是一个浮点数,
    而不是一个有理数,隐式类型转换的缺点

一般来说,越有经验的 C++程序员就越喜欢避开类型转换运算符。例子,在打印Rational类实例时,你忘了为 Rational 对象定义 operator<<。你可能想打印操作将失败,因为没有合适的的 operator<<被调用。但是你错了。当编译器调用 operator<<时,会发现没有这样的函数存在,但是它会试图找到一个合适的隐式类型转换顺序以使得函数调用正常运行。类型转换顺序的规则定义是复杂的,但是在现在这种情况下,编译器会发现它们能调用Rational::operator double 函数来把 r 转换为 double 类型。所以上述代码打印的结果是一个浮点数,而不是一个有理数。这样的函数有时候会引起预料之外的调用。可以用显示的转换函数替代

构造函数用 explicit 声明,如果这样做,编译器会拒绝为了隐式类型转换而调用构造函数。显式类型转换依然合法。

条款6:区别 increament/decrement 操作符的前置(prefix)和后置(postfix)形式

参考文章:《More Effective C++》笔记_more effective c++ pdf github-CSDN博客

More Effective C++-CSDN博客

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

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

相关文章

IDC MarketScape 低/无代码厂商评估:得帆信息被评为领导者

《IDC MarketScape:中国低代码/无代码开发平台2023年厂商评估 》报告正式发布。报告从战略与能力两大方向&#xff0c;在产品和功能、客户交付服务能力、营销和销售能力、伙伴与生态、商业战略模式等多个维度对国内低/无代码厂商进行全面评估。 得帆信息凭借战略与能力双项领先…

电子电器架构网络演化 —— 车载以太网TSN

电子电器架构网络演化 —— 车载以太网TSN 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消…

VBA中类的解读及应用第八讲:实现定时器功能的自定义类事件

《VBA中类的解读及应用》教程【10165646】是我推出的第五套教程&#xff0c;目前已经是第一版修订了。这套教程定位于最高级&#xff0c;是学完初级&#xff0c;中级后的教程。 类&#xff0c;是非常抽象的&#xff0c;更具研究的价值。随着我们学习、应用VBA的深入&#xff0…

uniapp微信小程序投票系统实战 (SpringBoot2+vue3.2+element plus ) -用户信息修改实现

锋哥原创的uniapp微信小程序投票系统实战&#xff1a; uniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )_哔哩哔哩_bilibiliuniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )共计21条视频…

如何通过bat文件启动应用程序

说明&#xff1a;在windows上&#xff0c;任何应用程序都是通过.exe启动的。我们可以通过配置环境的方式&#xff0c;将应用程序的路径配置到环境变量path变量里&#xff0c;这样就可以使用cmd窗口&#xff0c;敲应用程序的名称来启动应用程序。 如下&#xff0c;可启动wps应用…

Vue-8、Vue事件处理

1、点击事件 <!DOCTYPE html> <html lang"en" xmlns:v-model"http://www.w3.org/1999/xhtml" xmlns:v-bind"http://www.w3.org/1999/xhtml"xmlns:v-on"http://www.w3.org/1999/xhtml"> <head><meta charset&quo…

Nginx location 配置 - Part 2

接上文 链接: Nginx 简介和入门 - part1 上文 我们简单地在 nginx 创建了3个虚拟主机&#xff0c; 虽然这个3个主机都是用占用80端口 但是我们可以用不同的域名来实现区分访问3台虚拟主机。 但是&#xff0c; 实际项目上&#xff0c; 我们更加多地会使用location 配置而不是…

Docker实战08|Docker管道及环境变量识别

上一篇文章中&#xff0c;讲解了如何通过Go语言实现对Docker Cgroup的资源限制 具体文章可见《Docker就应该这么学-07》 有需要的小伙伴可以回顾一下。 接下来本文会详细介绍一下Docker 管道及环境变量识别 管道及环境变量识别 获取代码 git clone https://gitee.com/mjr…

物理机部署三节点Kafka集群

一、部署Kafka集群 官方下载地址&#xff1a;http://kafka.apache.org/downloads.html上传安装包到102的/opt/software目录下 解压安装包到/opt/module/目录下&#xff0c;修改解压包名为kafka 修改config目录下的配置文件server.properties内容 #broker的全局唯一编号&#…

【漏洞复现】ActiveMQ文件上传漏洞(CVE-2016-3088)

Nx01 产品简介 Apache ActiveMQ是Apache软件基金会所研发的开放源代码消息中间件。ActiveMQ是消息队列服务&#xff0c;是面向消息中间件&#xff08;MOM&#xff09;的最终实现&#xff0c;它为企业消息传递提供高可用、出色性能、可扩展、稳定和安全保障。 Nx02 漏洞描述 Ap…

excel统计分析——LSD多重比较

参考资料&#xff1a;生物统计学 一篇教你搞定显著性差异分析abcd字母标记法 LSD&#xff08;least significant difference&#xff0c;最小显著差数法&#xff09;是R. A. Fisher提出的&#xff0c;又称为Fisher LSD检验法&#xff0c;是最早用于检验各组均数间两两差异的方…

Unity | 渡鸦避难所-6 | 有限状态机控制角色行为逻辑

1 有限状态机简介 有限状态机&#xff08;英语&#xff1a;finite-state machine&#xff0c;缩写&#xff1a;FSM&#xff09;&#xff0c;简称状态机&#xff0c;是表示有限个状态以及在这些状态之间的转移和动作等行为的数学计算模型 在游戏开发中应用有限状态机&#xff…

NoSQL概述与Redis入门-redis安装与测试

一、Nosql概述 1、为什么使用Nosql 1、单机Mysql时代 90年代,一个网站的访问量一般不会太大&#xff0c;单个数据库完全够用。随着用户增多&#xff0c;网站出现以下问题 数据量增加到一定程度&#xff0c;单机数据库就放不下了数据的索引&#xff08;B Tree&#xff09;,一个…

38.深入MySQL

深入MySQL 索引 索引是关系型数据库中用来提升查询性能最为重要的手段。关系型数据库中的索引就像一本书的目录&#xff0c;我们可以想象一下&#xff0c;如果要从一本书中找出某个知识点&#xff0c;但是这本书没有目录&#xff0c;这将是意见多么可怕的事情&#xff01;我们…

【JaveWeb教程】(16) SpringBootWeb之 分层解耦 详细代码示例讲解

目录 SpringBootWeb请求响应3. 分层解耦3.1 三层架构3.1.1 介绍3.1.2 代码拆分 3.2 分层解耦3.2.1 耦合问题3.2.2 解耦思路 3.3 IOC&DI3.3.1 IOC&DI入门3.3.2 IOC详解3.3.2.1 bean的声明3.3.2.2 组件扫描 3.3.3 DI详解 SpringBootWeb请求响应 3. 分层解耦 3.1 三层架…

【UE Niagara学习笔记】01 - 浮动的蒲公英

目录 效果 步骤 一、创建材质 二、创建Niagara粒子 2.1 创建Niagara模板 2.2 通过用户参数设置粒子大小 2.3 设置数量、风速、透明度变化 2.4 设置粒子旋转 效果 步骤 一、创建材质 1. 在虚幻商城中把“Realistic Starter VFX Pack Vol 2”添加到项目中&#xff…

机器学习周刊 第4期:动手实战人工智能、计算机科学热门论文、免费的基于ChatGPT API的安卓端语音助手、每日数学、检索增强 (RAG) 生成技术综述

LLM开发者必读论文&#xff1a;检索增强&#xff08;RAG&#xff09;生成技术综述&#xff01; 目录&#xff1a; 1、动手实战人工智能 Hands-on Al2、huggingface的NLP、深度强化学习、语音课3、Awesome Jupyter4、计算机科学热门论文5、LLM开发者必读论文:检索增强 (RAG) 生…

用css给宽高不固定的矩形画对角线

.kong{width: 200rpx;height: 76rpx;background: linear-gradient(to bottom right, #E5E5E5 0%, rgba(0, 0, 0, 0.1) calc(50% - 1px),#175CFF 50%, rgba(0, 0, 0, 0.1) calc(50% 1px),rgba(0, 0, 0, 0.1) 100%);}参考&#xff1a; https://blog.csdn.net/weixin_38779534/a…

GCN的使用和包的安装(超详细)

文章目录 工具包安装方法首先进入官网&#xff0c;找到安装包的地址进入后&#xff0c;找到自己的torch版本进入后&#xff0c;将每种对应的包都下载到本地&#xff0c;用本地命令安装然后就是本地安装了最后就是pip install pytorch_geometric 工具包安装方法 一定参考其GITH…

css选择器有哪些?优先级?哪些属性可以继承?

面试官&#xff1a;css选择器有哪些&#xff1f;优先级&#xff1f;哪些属性可以继承&#xff1f; 一、选择器 CSS选择器是CSS规则的第一部分 它是元素和其他部分组合起来告诉浏览器哪个HTML元素应当是被选为应用规则中的CSS属性值的方式 选择器所选择的元素&#xff0c;叫做…