Effective C++ 2e Item5

Effective_C++2e Effective_C++2eEffective_C++2eEffective_C++2eEffective_C++2eEffective_C++2eEffective_C++2eEffective_C++2e 立即下载

内存管理

C++中涉及到的内存的管理问题可以归结为两方面:正确地得到它和有效地使用它。好的程序员会理解这两个问题为什么要以这样的顺序列出。因为执行得再快、体积再小的程序如果它不按你所想象地那样去执行,那也一点用处都没有。“正确地得到”的意思是正确地调用内存分配和释放程序;而“有效地使用”是指写特定版本的内存分配和释放程序。这里,“正确地得到”显得更重要一些。

然而说到正确性,C++其实从C继承了一个很严重的头疼病,那就是内存泄露隐患。虚拟内存是个很好的发明,但虚拟内存也是有限的,并不是每个人都可以最先抢到它。

在C中,只要用malloc分配的内存没有用free返回,就会产生内存泄露。在C++中,肇事者的名字换成了new和delete,但情况基本上是一样的。当然,因为有了析构函数的出现,情况稍有改善,因为析构函数为所有将被摧毁的对象提供了一个方便的调用delete的场所。但这同时又带来了更多的烦恼,因为new和delete是隐式地调用构造函数和析构函数的。而且,因为可以在类内和类外自定义new和delete操作符,这又带来了复杂性,增加了出错的机会。下面的条款(还有条款M8)将告诉你如何避免产生那些普遍发生的问题。


条款5:对应的new和delete要采用相同的形式

下面的语句有什么错?
    string *stringArray = new string[100];

    ...

    delete stringArray;

一切好象都井然有序——一个new对应着一个delete——然而却隐藏着很大的错误:程序的运行情况将是不可预测的。至少,stringArray指向的100个string对象中的99个不会被正确地摧毁,因为他们的析构函数永远不会被调用。

用new的时候会发生两件事。首先,内存被分配(通过operator new 函数,详见条款7-10和条款M8),然后,为被分配的内存调用一个或多个构造函数。用delete的时候,也有两件事发生:首先,为将被释放的内存调用一个或多个析构函数,然后,释放内存(通过operator delete 函数,详见条款8和M8)。对于 delete来说会有这样一个重要的问题:内存中有多少个对象要被删除?答案决定了将有多少个析构函数会被调用。

这个问题简单来说就是:要被删除的指针指向的是单个对象呢,还是对象数组?这只有你来告诉delete。如果你在用delete时没用括号,delete就会认为指向的是单个对象,否则,它就会认为指向的是一个数组:
    string *stringPtr1 = new string;

    string *stringPtr2 = new string[100];

    ...

    delete stringPtr1;           // 删除一个对象
    delete [] stringPtr2;        // 删除对象数组
 
如果你在stringPtr1前加了"[]"会怎样呢?答案是:那将是不可预测的;如果你没在stringPtr2前没加上"[]"又会怎样呢?答案也是:不可预测。而且对于象int这样的固定类型来说,结果也是不可预测的,即使这样的类型没有析构函数。所以,解决这类问题的规则很简单:如果你调用new时用了[],调用delete时也要用[]。如果调用new时没有用[],那调用delete时也不要用[]。

在写一个包含指针数据成员,并且提供多个构造函数的类时,牢记这一规则尤其重要。因为这样的话,你就必须在所有初始化指针成员的构造函数里采用相同的new的形式。否则,析构函数里将采用什么形式的delete呢?关于这一话题的进一步阐述,参见条款11。

这个规则对喜欢用typedef的人来说也很重要,因为写typedef的程序员必须告诉别人,用new创建了一个typedef定义的类型的对象后,该用什么形式的delete来删除。举例如下:
    typedef string AddressLines[4];      // 一个人的地址,共4行,每行一个string
因为AddressLines是个数组,使用new:
    string *pal = new AddressLines;      // 注意"new AddressLines"返回string*, 和
                                                       // "new string[4]"返回的一样
delete时必须以数组形式与之对应:
    delete pal;                          // 错误!

    delete [] pal;                       // 正确

为了避免混乱,最好杜绝对数组类型用typedefs。这其实很容易,因为标准C++库(见条款49)包含有stirng和vector模板,使用他们将会使对数组的需求减少到几乎零。举例来说,AddressLines可以定义为一个字符串(string)的向量(vector),即AddressLines可定义为vector<string>类型。

从Xilinx FPGA到MIPI DSI LCD屏:手撸代码的实战经验分享 本文分享了使用Xilinx FPGA驱动MIPI DSI LCD屏的实战经验。作者从依赖官方IP核失败,到与底层D-PHY IP缠斗,最终通过手撸代码,直接配置GTY收发器原语并实现完整的D-PHY与DSI协议栈,成功点亮屏幕。文章详细剖析了协议细节、Vivado工具链的调试技巧与避坑指南,为FPGA工程师提供了从理论到实践的宝贵参考。 阅读详情

相关推荐

5个IO口驱动188数码管:查理复用算法在TM52F1363上的极致应用

本文深入解析了如何利用查理复用算法,在TM52F1363单片机上仅用5个IO口驱动188数码管。通过精密的硬件连接与软件时序控制,结合高阻态和动态扫描策略,实现了在极致资源限制下的稳定显示,为成本敏感型嵌入式产品提供了高效的IO复用解决方案。

numpy6sculptor的博客 478

Effective C++ 2e Item12

条款12: 尽量使用初始化而不要在构造函数里赋值看这样一个模板,它生成的类使得一个名字和一个T类型的对象的指针关联起来。templateclass NamedPtr {public:  NamedPtr(const string& initName, T *initPtr);  ...private:  string name;  T *ptr;};(因为有指针成员的对象在进行拷贝

lostmouse的专栏 948

STM32与AD7606的SPI通信优化:提升高精度数据采集效率

本文深入探讨了STM32与AD7606的SPI通信优化策略,旨在提升高精度数据采集系统的效率与稳定性。文章从硬件连接、电源去耦、PCB布局等基础环节入手,详细解析了软件驱动中SPI模式配置、DMA应用及精准时序控制等关键优化技术,并提出了系统级的性能提升方案,帮助开发者解决高速采样下的数据跳动、效率瓶颈等实际问题。

weixin_29192211的博客 393

Effective C++ 2e Item10

 条款10. 如果写了operator new就要同时写operator delete让我们回过头去看看这样一个基本问题:为什么有必要写自己的operator new和operator delete?答案通常是:为了效率。缺省的operator new和operator delete具有非常好的通用性,它的这种灵活性也使得在某些特定的场合下,可以进一步改善它的性能。尤其在那些需要动态分

lostmouse的专栏 1190

Fortigate 在AWS中配置HA

方案1: 1、将两台服务器配置在相同可用区中,使用飞塔原生HA功能,可以实现配置同步功能。 2、配置SSLVPN,在主服务器不可用时,可以实现自动切换到备用服务器继续提供VPN服务。 当前问题: 1、主挂掉后可以自动切换到备,但是原主服务器修复后不会自动切换到主状态。 2、如下图所示切换中丢包明显,需要客户端开启“保持连接”功能。 配置过程如下: 1、整体架构 2、创建VPC和子网,如下图所示...

子苏蓝莓的博客 892

ENSP内使用wireshark进行抓包,并且解析icmp报文

前四位:54 89 98 e8 20 38 为ip报文包的mac地址也就是物理地址。一开始进行抓包是没有icmp报文的,需要我们在ensp中使用pc1请求联通pc9。协议编号后分别为:ip版本、ip首部报文长度、服务类型、ip报文总长度。最后为校验和 、源ip地址、目的ip、从08 00开始为真正的数据。我们需要实验的端口为:0/0/4,也就是抓包第三个交换机内的报文。其中显示的icmp报文就是我们需要解析的ip报文。源mac地址后跟着的就是协议编号: 08 00。根据ip报文包的结构我们进行解析。

2301_81713278的博客 2140

Effective C++ 2e Item46

条款46: 宁可编译和链接时出错,也不要运行时出错除了极少数情况下会使C++抛出异常(例如,内存耗尽 ---- 见条款7)外,运行时错误的概念和C++没什么关系,就象在C中一样。没有下溢,上溢,除零检查;没有数组越界检查,等等。一旦程序通过了编译和链接,你就得靠自己了 ---- 一切后果自负。这很象跳伞运动,一些人从中找到了刺激,另一些人则吓得摔成了残废。这一思想背后的动机当然在于效率:没有运

lostmouse的专栏 1167

C# Modbus通信从入门到精通(2)——Modbus RTU协议原理

本文详细的介绍了Modbus RTU协议的原理,由多年经验高级工程师实战总结而成,绝对干货!

qq_34059233的博客 6389

Effective C++ 2e Item1

 从C转向C++对每个人来说,习惯C++需要一些时间,对于已经熟悉C的程序员来说,这个过程尤其令人苦恼。因为C是C++的子集,所有的C的技术都可以继续使用,但很多用起来又不太合适。例如,C++程序员会认为指针的指针看起来很古怪,他们会问:为什么不用指针的引用来代替呢?C是一种简单的语言。它真正提供的只有有宏、指针、结构、数组和函数。不管什么问题,C都靠宏、指针、结构、数组和函数来解决。而C

lostmouse的专栏 1488

Allegro如何用自带的功能将线段变成铜皮操作指导

在做PCB设计的时候,有时根据设计需要将线段变成铜皮,可以借助辅助工具来实现这一操作,但是Allegro自身也自带这个功能,如下图。勾选Delete original objects。如何用自带的功能将线段变成铜皮操作指导。勾选Convert to shape,需要把这段走线变成铜皮。

weixin_54787054的博客 2946

AI自瞄原理剖析(四)从Yolo推理坐标到屏幕坐标:基于FOV视角与焦距的坐标变换与精准瞄准

从Yolo推理框架得到的坐标到屏幕坐标的转换是一个涉及到FOV视角、焦距以及分辨率的复杂过程。通过数学公式,我们可以将推理框坐标反推为游戏内的实际坐标,并最终映射到屏幕坐标系中。利用这些信息,AI自瞄系统能够精确计算出准星从当前位置移动到敌人位置的距离,实现精准的自动瞄准。通过这种方法,AI自瞄系统能够在不同的游戏环境下灵活应对,提供高度精确的操作体验。在AI自瞄系统中,目标检测仅仅是第一步,获取到预测框的坐标后,我们还需要将这些坐标转换为实际屏幕上的精确位置。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 1334

Effective C++ 2e Item15

条款15: 让operator=返回*this的引用C++的设计者Bjarne Stroustrup下了很大的功夫想使用户自定义类型尽可能地和固定类型的工作方式相似。这就是为什么你可以重载运算符,写类型转换函数(见条款M5),控制赋值和拷贝构造函数,等等。他做了这么多努力,那你最少也该继续做下去。让我们看看赋值。用固定类型的情况下,赋值操作可以象下面这样链起来:int w, x, y,

lostmouse的专栏 1079

基于Cesium实现,动态水面+大坝排水动画

一、绘制面状水域,使用水波纹理,进行渲染,水体透明,可以看到底色。三、使用粒子系统,将喷泉改变方向,加上重力设置,实现排水动画。二、绘制线状三维体,用作模拟大坝拦截效果。四、最后,模拟水位上升,进行淹没分析,

一醉千秋的专栏 1421

Effective C++ 2e Item50

条款50: 提高对C++的认识C++中有很多 "东西":C,重载,面向对象,模板,例外,名字空间。这么多东西,有时让人感到不知所措。怎么弄懂所有这些东西呢?C++之所以发展到现在这个样子,在于它有自己的设计目标。理解了这些设计目标,就不难弄懂所有这些东西了。C++最首要的目标在于:· 和C的兼容性。很多很多C还存在,很多很多C程序员还存在。C++利用了这一基础,并建立在 ---- 我是

lostmouse的专栏 1376

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Effective C++ 2e Item18

类和函数:设计与声明在程序中声明一个新类将导致产生一种新的类型:类的设计就是类型设计。可能你对类型设计没有太多经验,因为大多数语言没有为你提供实践的机会。在C++中,这却是很基本的特性,不是因为你想去做才可以这么做,而是因为每次你声明一个类的时候实际上就在做,无论你想不想做。设计一个好的类很具有挑战性,因为设计好的类型很具有挑战性。好的类型具有自然的语法,直观的语义和高效的实现。在C++中

lostmouse的专栏 1010

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Effective C++ 2e Item3

条款3:尽量用new和delete而不用malloc和freemalloc和free(及其变体)会产生问题的原因在于它们太简单:他们不知道构造函数和析构函数。假设用两种方法给一个包含10个string对象的数组分配空间,一个用malloc,另一个用new:    string *stringArray1 =      static_cast(malloc(10 * sizeof(strin

lostmouse的专栏 1230

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

Effective C++ 2e Item35

继承和面向对象设计很多人认为,继承是面向对象程序设计的全部。这个观点是否正确还有待争论,但本书其它章节的条款数量足以证明,在进行高效的C++程序设计时,还有更多的工具听你调遣,而不仅仅是简单地让一个类从另一个类继承。然而,设计和实现类的层次结构与C语言中的一切都有着根本的不同。只有在继承和面向对象设计领域,你才最有可能从根本上重新思考软件系统构造的方法。另外,C++提供了多种很令人困惑的面

lostmouse的专栏 855

Effective C++ 2e Item29

类和函数: 实现C++是一种高度类型化的语言,所以,给出合适的类和模板的定义以及合适的函数声明是整个设计工作中最大的一部分。按理说,只要这部分做好了,类、模板以及函数的实现就不容易出问题。但是,往往人们还是会犯错。犯错的原因有的是不小心违反了抽象的原则:让实现细节可以提取类和函数内部的数据。有的错误在于不清楚对象生命周期的长短。还有的错误起源于不合理的前期优化工作,特别是滥用inline关

lostmouse的专栏 1157

Effective C++ 2e Item26

条款26: 当心潜在的二义性每个人都有思想。有些人相信自由经济学,有些人相信来生。有些人甚至相信COBOL是一种真正的程序设计语言。C++也有一种思想:它认为潜在的二义性不是一种错误。这是潜在二义性的一个例子:class B;                    // 对类B提前声明                            // class A {public:  A(

lostmouse的专栏 923

Effective C++ 2e Item23

条款23: 必须返回一个对象时不要试图返回一个引用据说爱因斯坦曾提出过这样的建议:尽可能地让事情简单,但不要过于简单。在C++语言中相似的说法应该是:尽可能地使程序高效,但不要过于高效。一旦程序员抓住了“传值”在效率上的把柄(参见条款22),他们会变得十分极端,恨不得挖出每一个隐藏在程序中的传值操作。岂不知,在他们不懈地追求纯粹的“传引用”的过程中,他们会不可避免地犯另一个严重的错误:传递

lostmouse的专栏 978

Effective Modern C++ Item 5

啊,写出下面的代码是简单愉快的,int x; 等一下,该死。我忘记初始化了,因此它的值是不确定的。

ねぇ。あなたは何色になりたい 523

Effective C++【学习笔记】Item2

Accustoming yourself to C++ ------------------------------------------------------------------------------------ Item2: Prefer consts, enums, and inlines to #defines. 换句话说: Prefer the compiler to ...

cyy2learn的博客 324

c++ item

C++书单: 1:第一本   基础好一些的,可以看Stanley B. Lippman的C++ Primer,基础不太好的话,可以看Stanley B. Lippman的  Essential C++ 2:第二本   Pike和Kernighan的The Practice of Programming 3:第三本   Bruce Eckel写的、台湾候捷译的Thinking in C+

u012526180的专栏 3020

Item 5:那些被C++默默地声明和调用的函数 Effective C++笔记

Item 5: Know what functions C++ silently writes and calls 在C++中,编译器会自动生成一些你没有显式定义的函数,它们包括:构造函数、析构函数、复制构造函数、=运算符。 有时为了符合既有设计,我们不希望自动生成这些函数,我们可以把它们显式声明为private。 此时在使用这些类的客户看来,它们就像不存在一样。 clas

分享技术,共建开放平台 1005

重读经典-《Effective C++》Item2:尽量以const,enum,inline替换#define

○ 静态常量数据成员可以在类内初始化(即类内声明的同时初始化),也可以在类外,即类的实现文件中初始化,不能在构造函数中初始化,也不能在构造函数的初始化列表中初始化; ○ 静态非常量数据成员只能在类外,即类的实现文件中初始化,也不能在构造函数中初始化,不能在构造函数的初始化列表中初始化; ○ 非静态的常量数据成员不能在类内初始化,也不能在构造函数中初始化,而只能且必须在构造函数的初始化列表中初始化; ○ 非静态的非常量数据成员不能在类内初始化,可以在构造函数中初始化,也可以在构造函数的初始化列表

学习,思考,记录,分享。 4283

Modern Effective C++ item 15:尽可能的使用constexpr

当constexpr应用于函数时,表示函数可以在编译期执行,因为参数也是编译期常量。常量表达式构造函数拥有和常量表达式函数相同的退化特性,当它的实参不是常量表达式的时候,构造函数可以退化为普通构造函数,当然,这么做的前提是类型的声明对象不能为常量表达式值。正常工作,因为 10 是一个常量表达式,size(10) 可以在编译时计算其结果,并用于初始化 constexpr 变量 s_constexpr。constexpr还能定义一个常量表达式函数,即constexpr函数,常量表达式函数的返回值可以在编译。

_ 1120
上一篇: Effective C++ 2e Item4
下一篇: Effective C++ 2e Item6
lostmouse
博客等级 码龄26年 22粉丝 63原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值