代码设计原则
-
单一职责原则(Single Responsibility Principle,SRP):一个类应该只有一个引起它变化的原因。每个类应该只关注单一的职责或功能。
-
开放封闭原则(Open-Closed Principle,OCP):软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。通过扩展现有代码,而非修改代码,来引入新功能。
-
里氏替换原则(Liskov Substitution Principle,LSP):子类必须能够替换其基类,而不会破坏程序的正确性。子类应该保持基类的行为约束。
-
接口隔离原则(Interface Segregation Principle,ISP):客户端不应该依赖于它们不需要的接口。应该创建小而专注的接口,而非大而笨重的接口。
-
依赖倒置原则(Dependency Inversion Principle,DIP):高层模块不应该依赖低层模块,而应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。
-
迪米特法则(Law of Demeter,LoD):一个对象应该对其他对象有尽可能少的了解。一个类应该对其它的类保持最小的了解,只与直接的朋友进行交流。
这些原则可以指导开发人员设计出低耦合、高内聚且易于扩展的代码结构,提高代码的可维护性和可重用性。
请注意,这只是对这些原则的简要概述,每个原则都有更详细的解释和指导。深入理解和应用这些原则可以帮助您编写更优雅和可靠的代码。
其他原则
除了SOLID原则之外,还有一些其他的代码设计原则和方法论,包括:
-
KISS原则(Keep It Simple, Stupid):保持代码简单易懂,避免过度复杂化。简单的代码更易于理解、维护和调试。
-
DRY原则(Don’t Repeat Yourself):避免代码重复。相同的代码应该抽象成可重用的模块或函数,减少重复的劳动和维护的复杂性。
-
YAGNI原则(You Aren’t Gonna Need It):不要为未来可能需要的功能编写代码。只在需要时添加功能,避免过度设计和过度工程。
-
高内聚低耦合(High Cohesion, Low Coupling):模块或类应该有清晰的职责,并与其他模块或类之间保持松散的耦合关系。高内聚表示模块内部的元素彼此相关,低耦合表示模块之间的依赖关系尽可能少。
-
设计模式(Design Patterns):设计模式是经过验证的解决特定问题的重复利用的方案。常见的设计模式包括工厂模式、单例模式、观察者模式等,可以提供灵活、可扩展和可维护的代码结构。
-
测试驱动开发(Test-Driven Development,TDD):在编写代码之前先编写测试用例,然后根据测试用例的需求来编写代码。这种方式强调以测试为驱动来设计和实现代码,可以提高代码的质量和可测试性。
-
领域驱动设计(Domain-Driven Design,DDD):DDD是一种通过对业务领域的深入理解来指导软件设计的方法。它强调将业务模型和业务规则直接体现在代码中,以更好地满足业务需求。
这些原则和方法论都有助于编写高质量、可维护和可扩展的代码。根据项目需求和实际情况,可以结合使用这些原则和方法论来指导代码设计和开发过程。
设计模式
设计模式是软件开发中常用的解决问题的经典方法和思想的总结,它们提供了一套被广泛认可的解决方案,可用于各种不同的情境和问题。下面是对23种常见的设计模式的概述:
- 创建型模式(Creational Patterns):
- 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供全局访问点。
- 工厂方法模式(Factory Method Pattern):定义创建对象的接口,但由子类决定实例化哪个类。
- 抽象工厂模式(Abstract Factory Pattern):提供一个接口来创建一系列相关或依赖对象的家族,而不需要指定具体类。
- 建造者模式(Builder Pattern):将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。
- 原型模式(Prototype Pattern):通过复制现有对象来创建新对象,避免了直接使用构造函数创建对象的开销。
- 结构型模式(Structural Patterns):
- 适配器模式(Adapter Pattern):将一个类的接口转换成客户希望的另一个接口。
- 桥接模式(Bridge Pattern):将抽象部分与其实现部分分离,使它们可以独立地变化。
- 组合模式(Composite Pattern):将对象组合成树形结构以表示”整体-部分”的层次结构。
- 装饰器模式(Decorator Pattern):动态地给对象添加额外的责任,通过包装(装饰)原始对象来扩展其功能。
- 外观模式(Facade Pattern):为子系统中的一组接口提供一个统一的接口,简化复杂系统的使用。
- 行为型模式(Behavioral Patterns):
- 策略模式(Strategy Pattern):定义一系列算法,将它们封装起来,并且使它们可以相互替换。
- 观察者模式(Observer Pattern):定义了对象之间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都会被通知并自动更新。
- 责任链模式(Chain of Responsibility Pattern):为请求创建一个接收对象的链,并沿着这条链传递该请求,直到有对象处理它。
- 命令模式(Command Pattern):将请求封装成对象,以便可以用不同的请求对客户进行参数化。
- 状态模式(State Pattern):允许对象在内部状态改变时改变它的行为,看起来就像是改变了它的类。
- 迭代器模式(Iterator Pattern):提供一种顺序访问聚合对象中各个元素的方法,而又不暴露其内部表示。
- 中介者模式(Mediator Pattern):用一个中介对象来封装一系列的对象交互,使对象之间不再直接相互引用。
- 备忘录模式(Memento Pattern):在不破坏对象的封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
- 面向对象模式(OOP Patterns):
- 模板方法模式(Template Method Pattern):定义一个算法的骨架,将一些步骤延迟到子类中实现。
- 工厂模式(Factory Pattern):定义一个创建对象的接口,但由子类决定实例化哪个类。
- 原型模式(Prototype Pattern):通过复制现有对象来创建新对象,避免了直接使用构造函数创建对象的开销。
- 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供全局访问点。
- 其他模式:
- 访问者模式(Visitor Pattern):封装一些作用于某种数据结构中各元素的操作,可以在不改变这些元素的类的前提下定义新的操作。
这些设计模式为解决各种软件开发中的常见问题提供了一套可行的解决方案,并且在实际开发中被广泛应用。了解和熟悉这些设计模式可以提高代码的可扩展性、可维护性和重用性。请注意,选择适当的设计模式要根据具体的需求和问题进行评估,并根据实际情况进行应用。
CAP
- CAP原则又称CAP定理,指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。
名言
-
计算机科学中只有两件难事:缓存失效和命名 —— 菲尔·卡尔顿
-
使非法状态无法表示 —— 亚伦·明斯基
-
首先使更改变得容易(警告:这可能很难),然后进行简单的更改 —— 肯特贝克
-
简单的事情应该简单,复杂的事情应该可能 —— 艾伦·凯
-
在软件可以重用之前,它首先必须是可用的 —— 拉尔夫·约翰逊
-
简单是可靠性的先决条件 —— 埃兹格·迪克斯特拉
-
坏味道是代码中的某些结构,暗示(有时强烈要求)重构的可能性 —— 马丁·福勒
-
对象思维将我们的注意力集中在问题空间而不是解决方案空间 —— 大卫·韦斯特
-
我 80% 的问题都是简单的逻辑错误。80% 的剩余问题是指针错误。剩下的问题就很难了 —— 马克·唐纳
-
编程语言是一种用于描述计算的符号系统。因此,一种有用的编程语言必须适用于描述(即程序的编写者和读者)和计算(即在计算机上的有效实现)。但是人类和计算机是如此不同,以至于很难找到非常适合两者功能的符号设备 —— R·坦南特
-
今天的大多数软件都非常像埃及金字塔,数以百万计的砖块堆叠在彼此的顶部,没有结构完整性,只是通过蛮力和成千上万的奴隶完成的 —— 艾伦·凯
-
如果我们希望用户喜欢我们的软件,我们应该将它设计成一个讨人喜欢的人 —— 艾伦·库珀
-
概念完整性是系统设计中最重要的考虑因素 —— 弗雷德里克·P·布鲁克斯
-
子类不应该总是共享其父类的所有特征,而是通过继承来实现。这会降低程序设计的灵活性。它还引入了在子类上调用方法的可能性,这些方法没有意义或由于方法不适用于子类而导致错误 —— 史蒂夫·克拉布尼克
-
我们相信,如果客户对他们所说的需求感到满意,那么设计就会很好。改变对我们的要求是客户的错 —— 罗伯特·马丁
-
我对 goto 语句并不是非常教条。我有一种不舒服的感觉,其他人正在把它变成一种宗教,好像编程的概念问题可以通过一个技巧,通过一种简单的编码纪律来解决 —— 埃兹格·迪克斯特拉
-
如果你今天能完成今天的工作,但你以一种你明天不可能完成明天的工作的方式去做,那么你就输了 —— 马丁·福勒
-
你不能教初学者自上而下的编程,因为他们不知道哪一端是向上的 —— 托尼·霍尔
-
今天的编程是软件工程师努力构建更大更好的白痴程序的竞赛,而宇宙试图产生更大更好的白痴。目前为止,宇宙胜 —— 里克·库克
-
无论你怎么看(DRY 或懒惰),想法都是一样的:让你的程序灵活。当变化来临时(而且总是这样),你会更容易随它而变化 —— 克里斯·派恩
-
重复是精心设计的系统的主要敌人 —— 罗伯特·马丁
-
乐观主义是编程的职业病,用户反馈则是治疗方法 —— 肯特贝克
-
诀窍用来解决您遇到的问题,而不是您想要的问题 —— 布拉姆·科恩
-
面向对象的编程语言支持封装,从而提高软件的重用、细化、测试、维护和扩展能力。只有在设计过程中最大化封装,才能实现这种支持的全部好处 —— 丽贝卡·维尔夫斯-布洛克
-
软件团队最大的问题是确保每个人都了解其他人在做什么 —— 马丁·福勒
-
将对象变量(实例变量)视为数据属性然后根据共享属性创建层次结构会产生错误。始终根据共享行为创建层次结构 —— 大卫·韦斯特
-
你可以通过提及另一种计算机语言来证明任何事情 —— 拉里·沃尔
-
计算的目的是洞察力,而不是数字 —— 理查德·汉明
-
告诉程序员已经有一个库可以做 X 就像告诉词曲作者已经有一首关于爱情的歌 —— 皮特·科德尔
-
在纯函数式程序中,[常量] 的值永远不会改变,但它一直在改变!一个悖论! —— 乔尔·斯波尔斯基
-
当有人说,“我想要一种编程语言,我只需要说出我想做的事情”,就给他一根棒棒糖 —— 艾伦·佩利斯
-
数据结构只是一种愚蠢的编程语言 —— 比尔·戈斯珀
-
黑客是傲慢的极客浪漫主义者。他们缺乏细心的探究精神 —— 布鲁斯·斯特林
-
软件是一种气体;它膨胀以填满它的容器 —— 内森·梅尔沃德
-
科学是我们理解得足以向计算机解释的东西。艺术是我们所做的一切 —— 唐纳德·克努斯
-
你编写的代码使你成为一名程序员。你删除的代码使你成为一个好人。你不必编写的代码会让你成为一个伟大的人 —— 马里奥·福斯科
-
最终的源代码是真正的软件设计 —— 杰克·里夫斯
-
学会不要立即添加太多功能,并构建和测试核心思想 —— 利亚卡尔弗
-
如果它不起作用,那么它不起作用的速度有多快都没有关系 —— 米奇·拉维拉
-
编程的主要活动不是新的独立程序的产生,而是对已有程序的整合、修改和解释 —— 特里·维诺格拉德
-
我无法抗拒放入空引用的诱惑,仅仅因为它很容易实现。这导致了无数错误、漏洞和系统崩溃,在过去的四十年里,这些问题可能造成了 10 亿美元的痛苦和损失 —— 托尼·霍尔
-
在没有合同的情况下编写类类似于在没有规范的情况下生产工程组件(电路、VLSI(超大规模集成)芯片、桥接器、引擎……)。没有专业工程师会考虑这个想法 —— 伯特兰·迈耶
-
编程不是打字,而是思考 —— 里奇·希基
-
没有什么比临时 hack 更永恒的了 —— 凯尔·辛普森
-
架构是耦合和内聚之间的张力 —— 尼尔福特
-
知道应该检查什么地方并确保程序在出错时快速失败是一门艺术。这种选择是简化艺术的一部分 —— 沃德·坎宁安
-
如果一开始就没有正确地指明或理解,那么再多的优雅的编程或技术都无法解决问题 —— 米尔特·布莱斯
-
无论您的职业抱负是什么,学习编码都是有用的 —— 阿里安娜赫芬顿
-
复杂性与智能无关,简单性才是 —— 拉里·博西迪
-
稍后等于永不 —— 勒布朗法则
-
如有疑问,请使用蛮力 —— 肯·汤普森
-
计算机科学教育不能使任何人成为专家程序员,正如学习画笔和颜料不能使某人成为专家画家一样 —— E. 雷蒙德
-
图不是模型。模型不是图表。它是一种抽象,是一组概念和它们之间的关系 —— 埃里克·埃文斯
-
思考不是操纵语言的能力;这是操纵概念的能力 —— 莱斯利·兰波特
-
对象共享的信息可能是也可能不是该对象结构的一部分。也就是说,对象可能会计算信息,或者它可能会将信息请求委托给另一个对象 —— 丽贝卡·维尔夫斯·布鲁克斯
-
如果有人声称拥有完美的编程语言,那么他要么是傻瓜,要么是推销员,或者两者兼而有之 —— 比亚恩·斯特劳斯楚普
-
程序和人一样,都会变老。我们无法预防衰老,但我们可以了解其原因,限制其影响并扭转一些损害 —— 马里奥·福斯科
-
如果两者都被冻结,那么在水上行走和根据需求文档开发软件都很容易 —— 爱德华·贝拉德
-
软件实体(类、模块、函数等)应该对扩展开放,对修改关闭 —— 伯特兰·迈耶
-
对我来说,编程不仅仅是一门重要的实用艺术。在知识的基础上,这也是一项巨大的事业 —— 格蕾丝·霍珀
-
编程语言是一种对我们的思维习惯有着深远影响的工具 —— 埃兹格·迪克斯特拉
-
好的设计增加价值的速度快于增加成本的速度 —— 托马斯·C·盖尔
-
我终于明白了什么是“向上兼容”。这意味着我们可以保留所有旧错误 —— 丹尼·范·塔塞尔
-
使忽略错误条件变得困难。不要在返回值中隐藏错误码 —— 史蒂夫·马奎尔
-
过早优化是万恶之源 —— 唐纳德·克努斯
-
面向对象编程通过管理复杂性来增加这些指标的价值。处理复杂性的最有效工具是抽象。可以使用许多类型的抽象,但封装是抽象的主要形式,在面向对象编程中通过它管理复杂性 —— 丽贝卡·维尔夫斯-布洛克
-
类型本质上是关于程序的断言。而且我认为让事情尽可能绝对简单是有价值的,包括甚至不说类型是什么 —— 丹尼尔·英格尔斯
-
我不是一个伟大的程序员;我只是一个有很好习惯的好程序员 —— 肯特贝克
-
不要自动化无纪律的工作流程。客户的管理解决不了的,电脑也解决不了 —— 拉里·伯恩斯坦
-
技术由两种人主宰:一种是理解他们不了解的东西的人,另一种是管理他们不了解的东西的人 —— 阿奇博尔德推杆
-
只要有可能,窃取代码 —— 汤姆达夫
-
今天,大多数软件的存在不是为了解决问题,而是为了与其他软件交互 —— 安吉尔
-
提防携带螺丝刀的程序员 —— 伦纳德·布兰德温
-
上帝可以在六天内创造世界,因为他不必让它与以前的版本兼容 —— 马克·吐温
-
BASIC 之于计算机编程就像 QWERTY 之于打字一样 —— 西摩·派尔特
-
在任何特定时间点,我们的编程语言提供的功能都反映了我们对软件和编程的理解 —— R·E·费尔利
-
你认识的每一个伟大的开发人员都是通过解决他们没有资格解决的问题来实现的 —— 帕特里克·麦肯齐
-
PHP 是由无能的业余爱好者制造的小恶魔,而 Perl 是由技术娴熟但变态的专业人士制造的巨大而阴险的恶魔 —— 乔恩·里本斯
-
计算机科学中的任何问题都可以通过另一个间接层来解决 —— 大卫惠勒
-
我不能像对生物学那样对计算机科学充满信心。生物学很容易有 500 年的令人兴奋的问题需要研究 —— 唐纳德·克努斯
-
曾经有一台电脑在国际象棋上打败了我,但在跆拳道上却比不上我 ——飞利浦
-
科学家为学习而建造;工程师学习建造 —— 弗雷德布鲁克斯
-
发现的最大障碍不是无知,而是知识的错觉 —— 丹尼尔·布尔斯汀
-
记住,代码是你的房子,你必须住在里面 —— 迈克尔·C·羽毛
-
最好的性能提升是从非工作状态过渡到工作状态 —— J.奥斯特豪特
-
与其等待第一个可用的程序员变得有生产力,不如等待一个有生产力的程序员成为可用的 —— 史蒂夫·麦康奈尔
-
整个算术现在出现在机制的掌握之中 —— 查尔斯·巴贝奇
-
半个世纪以来,责备程序员一直是软件开发的主流方法:它尚未解决问题,因此是时候寻找不同的方向了 —— 鲍里斯·贝泽尔
-
如果您认为好的架构很昂贵,请尝试糟糕的架构 —— 布赖恩·富特和约瑟夫·约德
-
C++ 旨在让您表达想法,但如果您没有想法或不知道如何表达想法,C++ 不会提供太多帮助 —— 比亚恩·斯特劳斯楚普
-
唯一真正安全的系统是断电的,浇筑在混凝土块中并密封在有武装警卫的铅制房间内 —— 吉恩·斯帕福德
-
Bug 潜伏在角落里并聚集在边界处 —— 鲍里斯·贝泽尔
-
在编程中,困难的不是解决问题,而是决定解决什么问题 —— 保罗·格雷厄姆
-
我认为测试驱动的设计很棒。但是你可以测试你想要的一切,如果你不知道如何解决问题,你就不会得到解决方案 —— 彼得·诺维格
-
一个糟糕的程序员一年可以轻松地创造两个新工作 —— 大卫·帕纳斯
-
缺陷就是缺陷。你编写带有缺陷的代码是因为你这样做了。如果它是运行时安全语言,操作系统应该崩溃,而不是以可被利用的方式进行缓冲区溢出 —— 肯·汤普森
-
科学是我们理解得足以向计算机解释的东西,剩下的是艺术 —— 唐纳德·克努斯
-
能想像的人,能创造不可能的事 —— 图灵
-
培训师或顾问的作用是赋予客户能力,而不是让他自己变得不可或缺 —— 伯特兰·迈耶
-
正确性显然是首要品质。如果一个系统没有做它应该做的事情,那么关于它的其他一切都无关紧要 —— 伯特兰·迈耶
-
质量是免费的,但只适用于愿意为之付出高昂代价的人 —— 德马科和李斯特
-
没有什么比一套测试更能使系统更灵活 —— 罗伯特马丁
-
通过测试,我们可以快速且可验证地更改代码的行为。没有它们,我们真的不知道我们的代码是变得更好还是更糟 —— 迈克尔费切斯
-
有两种方法可以编写无错误的程序;只有第三种有效 —— 艾伦·J·佩利斯
-
通常,软件系统只有被实际使用并反复失败后才能很好地工作 —— 大卫·帕纳斯
-
随着测试变得更加具体,代码变得更加通用 —— 罗伯特马丁
-
每当我不得不思考以了解代码在做什么时,我都会问自己是否可以重构代码以使其更易理解 —— 马丁福勒
-
毫无疑问,面向对象的设计与传统的结构化设计方法有着根本的不同:它需要不同的分解思维方式,并且它产生的软件架构在很大程度上超出了结构化设计文化的领域 —— 格雷迪·布奇
-
我发明了“面向对象”这个词,而 C++ 并不是我所想的 —— 艾伦·凯
-
计算机擅长听从指令,但不擅长读心 —— 唐纳德·克努斯
c++ 面试相关
- RAII
- 内存管理功能问题
- • memory overrun:写内存越界
- • double free:同一块内存释放两次
- • use after free:内存释放后使用
- • wild free:释放内存的参数为非法值
- • access uninitialized memory:访问未初始化内存
- • read invalid memory:读取非法内存,本质上也属于内存越界
- • memory leak:内存泄露
- • use after return:caller访问一个指针,该指针指向callee的栈内内存
- • stack overflow:栈溢出
- 常用的解决内存错误的方法
- 代码静态检测
- 静态代码检测是指无需运行被测代码,通过词法分析、语法分析、控制流、数据流分析等技术对程序代码进行扫描
- 一些主流的静态代码检测工具,免费的cppcheck,clang static analyzer;商用的coverity,pclint等
- 代码动态检测
- 所谓的代码动态检测,就是需要再程序运行情况下,通过插入特殊指令,进行动态检测和收集运行数据信息,然后分析给出报告。
- 代码静态检测
- C++内存管理效率问题
- C++内存管理问题
- 频繁的new/delete势必会造成内存碎片化,使内存再分配和回收的效率下降;
- 尤其对于小块内存,堆内将产生越来越多不可用的碎片,导致“内存泄露”。而这种“泄露”现象使用 valgrind 是无法检测出来的。
- 常用解决上述问题的方案
- 内存池技术
- 内存池方案通常一次从系统申请一大块内存块,然后基于在这块内存块可以进行不同内存策略实现,可以比较好得解决上面提到的问题,一般采用内存池有以下好处:
- 1.少量系统申请次数,非常少(几没有) 堆碎片。
- 2.由于没有系统调用等,比通常的内存申请/释放(比如通过malloc, new等)的方式快。
- 3.可以检查应用的任何一块内存是否在内存池里。
- 4.写一个”堆转储(Heap-Dump)”到你的硬盘(对事后的调试非常有用)。
- 5.可以更方便实现某种内存泄漏检测(memory-leak detection)。
- 6.减少额外系统内存管理开销,可以节约内存;
- 内存池方案通常一次从系统申请一大块内存块,然后基于在这块内存块可以进行不同内存策略实现,可以比较好得解决上面提到的问题,一般采用内存池有以下好处:
- 内存池技术
- C++内存管理问题
- C++防内存泄漏🔥13招
- 🚫 不要返回对局部对象的引用:当函数返回时,控制权离开函数的作用域,局部对象会被自动销毁。因此,不要返回对局部对象的引用。
- 🚫 不要返回对new分配的指针的引用:使用new分配的内存如果没有手动delete,会导致内存泄漏。尤其是在中间函数中使用时,很容易忘记释放内存。
- 📝 避免使用裸指针:尽量避免使用裸指针,因为它们增加了内存泄漏的风险。
- 📝 使用智能指针:智能指针可以自动管理内存,减少内存泄漏的可能性。
- 📝 谨慎使用动态分配:动态分配的内存需要手动释放,否则会导致内存泄漏。在使用动态分配时,确保在不再需要时释放内存。
- 📝 检查内存泄漏:使用工具检查代码中的内存泄漏,确保所有分配的内存都被正确释放。
- 📝 考虑使用RAII:资源获取即初始化(RAII)是一种编程技术,通过将资源的管理与资源的创建紧密结合,确保资源在使用后被正确释放。
- 📝 避免在函数内部分配内存:在函数内部分配内存并返回引用或指针,可能会导致内存泄漏。尽量避免这种做法。
- 📝 使用局部静态对象:局部静态对象在函数外部可见,并且它们的生命周期与程序的生命周期相同。使用局部静态对象可以避免内存泄漏。
- 📝 避免在函数返回后使用对象:一旦函数返回,局部对象就会被销毁。避免在函数返回后使用这些对象,因为它们可能不再有效。
- 📝 避免在析构函数中分配内存:析构函数中分配的内存通常不会被自动释放。尽量避免在析构函数中分配内存。
- 📝 使用异常安全编程:异常安全编程可以确保即使在异常发生时,资源也会被正确释放。这对于避免内存泄漏非常有用。
- 📝 谨慎使用动态数组:动态分配的数组需要手动释放,否则会导致内存泄漏。在使用动态数组时,确保在不再需要时释放内存。
- 📝 检查内存分配失败:检查动态分配的内存是否成功分配。如果分配失败,可能会导致内存泄漏。
- 📝 避免在循环中分配内存:在循环中分配内存可能会导致内存泄漏。尽量避免在循环中分配内存。
- 📝 使用内存池:内存池是一种预分配内存的策略,可以减少动态分配的次数,从而减少内存泄漏的可能性。
- 📝 避免在析构函数中调用分配内存的函数:析构函数中分配的内存通常不会被自动释放。尽量避免在析构函数中调用分配内存的函数。
- 📝 使用RAII来管理资源:通过将资源的生命周期与资源的创建紧密结合,确保资源在使用后被正确释放。
- 📝 避免在函数内部使用new分配的内存:在函数内部使用new分配的内存可能会导致内存泄漏。尽量避免这种