More Effective C++:改善编程与设计(下)

目录

条款19:了解临时对象的来源

条款20:协助完成“返回值优化”

条款21:利用重载技术避免隐式类型转换

条款22:考虑以操作符复合形式(op=)取代其独身形式(op)

条款23:考虑使用其他程序库

条款24:了解virtual functions、multiple inheritance、virtual base classes、runtime type identification的成本

条款25:将constructors和non-member functions虚化

条款26:限制某个class所能产生的对象数量

条款27:要求(禁止)对象产生于heap之中

条款28:智能指针(smart pointers)


条款19:了解临时对象的来源

        产生临时对象通常发生于两种情况:
        一是当隐式类型转换时,但请注意其中涉及到引用权限的问题,如果发生隐式类型转换,产生的临时变量具有常性,那么不能使用non-const类型进行接受,这属于权限放大;
        二是当函数返回对象,需要进行返回值优化,
总结:临时对象很耗成本,因此你需要尽可能消除它们。

条款20:协助完成“返回值优化”

        如果返回值在函数栈桢回收时销毁,那么你不能使用引用返回或者指针返回,此时取别名或是指针指向的是一个已经死亡的对象,没有任何意义,但如果出了函数作用域仍然没有销毁,那么可以考虑使用引用返回的方式。 如果函数一定要以by-value的方式返回对象,你无法 消除之,在不同的场景你需要选择正确且高效的返回值优化方式。
总结:在不同的场景你需要选择正确且高效的返回值优化方式。如果一定要传值返回,请不要刻意优化。

条款21:利用重载技术避免隐式类型转换

        单参数的构造函数支持隐式类型转换, 那么这里建议你单独重载一个函数来进行特殊传 参,而不掉用隐式构造函数, 同时,请不要忘记增加太多的重载函数会影响程序效率。

条款22:考虑以操作符复合形式(op=)取代其独身形式(op)

        第一, 一般而言,复合操作符比其对应的独身版本效率高, 因为独身版本通常必须返回一个新对象,而我们必须因此负担一个临时对象的构造和析构的成本,至于复合版本则是直接将结果写入其左端自变量,所以不需要产生一个临时对象来放置返回值。
        第二, 独身版本较易撰写,调试,和维护,方便使用, 复合版本效率较高,你可以同时提供两个版本,并根据性能与便利性自由选择。

条款23:考虑使用其他程序库

        不同的程序库即使提供相似的机能,也往往表现出不同的性能取舍策略,所以一旦你找出程序的瓶颈,你应该思考是否有可能因为改用另一个程序库而移除了那些瓶颈,可以找找看是否存在另一个功能相近的程序库而其在效率上有较高的设计权重。如果有,改用它,可以大幅 改善程序性能。

条款24:了解virtual functions、multiple inheritance、virtual base classes、runtime type identification的成本

        当一个虚函数被调用时,编译器使用virtual tables和virtual table pointers(简写为vtbls和vptrs)。vtbl通常是一个函数指针数组,其中保存的是各个虚函数的函数指针, 使用虚函数的成本是一个vtbl数组空间以及一个额外指针vptr,以及类中的成员函数都有inline的属性,那么使用虚函数事实上等于放弃了inlining。 (如果虚函数通过对象被调用,倒是可以inlined,但大部分虚函数调用动作是通过对象的指针或者引用完成的,此类行为无法被inlined。)  
        上面是简单继承,再来看看多重继承,举例菱形继承,为了不引发二义性使用虚拟继承:
        如图所示,虚基类可能导致对象内的隐藏指针增加,而如果基类A有任何虚函数,内存布局会
增加更多的指针(用红笔标出)。

条款25:将constructors和non-member functions虚化

        这里说的当然不是将真正的构造函数虚化,如果你真的这么做了就会出大问题,由于虚函数 表是在初始化列表进行初始化的,那么如果你对函数进行虚化,那么需要先产生虚函数表,但虚 函数表在构造函数内部产生,这会导致程序混乱。好了, 这里是指将重复进行构造的动作单独设为一个函数,将此函数进行虚化,那么不同对象的构造函数来调用此函数就可以产生伪构造函数虚化的效果。
        就像constructors无法真正被虚化一样。non-member functions也是,就像我们认为应该能够以某个函数构造出不同类型的新对象一样,我们也认为应该可以让non-member functions的行为视其参数的动态类型而不同。

条款26:限制某个class所能产生的对象数量

        允许零个或一个对象:每当产生一个对象,就会调用这个class的构造函数,而阻止某个
class产出对象的最简单的方法就是将其constructors声明为private:
        Class myclass
        {
         private:
                myclass();
                myclass(const myclass& mc);
        }
        但这样移除了每个人产出对象的权利,但我们也可以选择性地解除这项约束,单例模式可以分为: 饿汉模式以及懒汉模式,前者不管怎么样都会生成一份对象,且存在初始化顺序混乱的问
题,而后者可以在必要时进行初始化,节省空间, 大致方式是将类的对象和create函数设为
static,将构造函数隐藏,在create函数中调用构造函数来进行初始化…
//这里作者模拟实现了一下:仅供参考
namespace hungry
{class Singleton{public:static Singleton& Create(){return slt;}bool Add(const pair<string, string>& kv){hash.insert(kv);return true;}void print(){for (const auto& e : hash){cout << e.first << " " << e.second << endl;}}private://先将构造函数私有化,防止轻易构造新对象Singleton(){}//以hash表为例子unordered_map<string, string> hash;//如何确保只有一个对象?使用staticstatic Singleton slt;//!!!记住要防止拷贝Singleton& operator=(const Singleton& st) = delete;Singleton(const Singleton& st) = delete;};Singleton Singleton::slt;//这里有点小奇怪,就理解为用singleton实例化singletion的slt吧
}//懒汉模式:直接用指针代替,需要的时候再进行实例化
namespace lazy
{class Singleton{public:static Singleton& Create(){if (slt == nullptr){slt = new Singleton;return *slt;}else{return *slt;}}// 一般单例不用释放。// 特殊场景:1、中途需要显示释放  2、程序结束时,需要做一些特殊动作(如持久化),比如写入文件static void Delete(){if (slt){delete slt;slt = nullptr;}else return;}bool Add(const pair<string, string>& kv){hash.insert(kv);return true;}void print(){for (const auto& e : hash){cout << e.first << " " << e.second << endl;}}class GC{public:~GC(){//垃圾回收站,这是为了方便多个单例对象需要持久化或者手动释放使用的Singleton::Delete();}};private://先将构造函数私有化,防止轻易构造新对象Singleton(){}~Singleton(){//在这里可以做一些持久化操作,将数据写入文件cout << "destructor" << endl;}unordered_map<string, string> hash;static Singleton* slt;static Singleton::GC gc;Singleton& operator=(const Singleton& st) = delete;Singleton(const Singleton& st) = delete;};Singleton* Singleton::slt=nullptr;Singleton::GC Singleton::gc;
}
        不同的对象构造状态:你可以使用继承的方式实现不同对象的不同构造,但是要小心内存
泄露,可以使用智能指针来管理对象。

条款27:要求(禁止)对象产生于heap之中

        允许对象产生于heap中:(禁止产生于栈中)
        有两种方法:1.将析构函数私有,这样无法直接实例化出对象;
                              2.将构造函数私有,使用static Create函数来执行new operator操作返回指针;
//只能在堆上实例化
class Heaponly1
{
public:Heaponly1(){ }void Delete(){delete this;//巧妙}private:~Heaponly1(){//...}//要防止在栈上创建空间,还要将拷贝构造和复制构造deleteHeaponly1& operator=(const Heaponly1& hp) = delete;Heaponly1(const Heaponly1& hp) = delete;
};class Heaponly2
{
public:static Heaponly2* Create(){return new Heaponly2;}
private:Heaponly2(){//...}Heaponly2& operator=(const Heaponly2& hp) = delete;Heaponly2(const Heaponly2& hp) = delete;
};
        禁止对象产生于heap中:(允许产生于栈中)
        有两种方法:1.将operator new函数delete,这样new operator就无法调用operator new;
                              2.将构造函数私有,使用static Create函数来在栈上产生一个对象,并返回引用;
//只能在栈上创建对象的类
class Stackonly1
{
public:static Stackonly1 Create(){Stackonly1 st;return st;}
private:Stackonly1(){}
};class Stackonly2
{
public:Stackonly2(){ }
private:void* operator new(size_t size) = delete;
};

条款28:智能指针(smart pointers)

        智能指针有auto_ptr、unique_ptr、shared_ptr、weak_ptr,其中auto_ptr存在指针悬空的 问题,unique_ptr只能管理一个对象,进行了反拷贝操作,shared_ptr使用引用计数,当计数减为0时释放内存,但是存在引用循环的问题,所以weak_ptr来专门解决引用循环的问题,不参与计数的改变,具体模拟实现可以参考作者往作。
C++ 智能指针底层逻辑揭秘:优化内存管理的核心技术解读-CSDN博客https://blog.csdn.net/Dai_renwen/article/details/147230673?spm=1001.2014.3001.5501

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

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

相关文章

VTK|类似CloudCompare的比例尺实现2-vtk实现

文章目录 实现类头文件实现类源文件调用逻辑关键问题缩放限制问题投影模式项目git链接实现类头文件 以下是对你提供的 ScaleBarController.h 头文件添加详细注释后的版本,帮助你更清晰地理解每个成员和方法的用途,尤其是在 VTK 中的作用: #ifndef SCALEBARCONTROLLER_H #de…

PostgreSQL 联合索引生效条件

最近面试的时候&#xff0c;总会遇到一个问题 在 PostgreSQL 中&#xff0c;联合索引在什么条件下会生效&#xff1f; 特此记录~ 前置信息 数据库版本 PostgreSQL 14.13, compiled by Visual C build 1941, 64-bit 建表语句 CREATE TABLE people (id SERIAL PRIMARY KEY,c…

SpringBoot项目里面发起http请求的几种方法

在Spring Boot项目中发起HTTP请求的方法 在Spring Boot项目中&#xff0c;有几种常用的方式可以发起HTTP请求&#xff0c;以下是主要的几种方法&#xff1a; 1. 使用RestTemplate (Spring 5之前的主流方式) // 需要先注入RestTemplate Autowired private RestTemplate restT…

《Python星球日记》 第90天:微调的概念以及如何微调大模型?

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、微调原理1. 什么是大模型微调?2. 为什么需要微调?3. 微调的基本流程4. 微调策略分类二、LoRA(Low-Rank Adaptation)技术详解1. LoRA的核…

机器学习-人与机器生数据的区分模型测试 - 模型融合与检验

模型融合 # 先用普通Pipeline训练 from sklearn.pipeline import Pipeline#from sklearn2pmml.pipeline import PMMLPipeline train_pipe Pipeline([(scaler, StandardScaler()),(ensemble, VotingClassifier(estimators[(rf, RandomForestClassifier(n_estimators200, max_de…

怎样免费开发部署自己的网站?

要免费开发自己的网站&#xff0c;您可以根据自己的技术水平和需求选择以下两种主要方式&#xff1a; 零基础用户&#xff1a;建议使用如WordPress.com、Weebly、Strikingly等平台&#xff0c;快速搭建网站。 有一定技术基础的用户&#xff1a;可选择自行开发网站&#xff0c;…

调用百度云API机器翻译

新建Python文件&#xff0c;叫 text_translator.py 输入 import requests import jsonAPI_KEY "glYiYVF2dSc7EQ8n78VDRCpa" # 替换为自己的API Key SECRET_KEY "kUlhze8OQZ7xbVRp" # 替换为自己的Secret Keydef main():# 选择翻译方向while True:di…

OpenAI与微软洽谈新融资及IPO,Instagram因TikTok流失四成用户

OpenAI与微软洽谈新融资及IPO 据悉&#xff0c;OpenAI 正与微软洽谈新融资及筹备 IPO&#xff0c;关键问题是微软在 OpenAI 重组后的股权比例。微软已投资超 130 亿美元&#xff0c;双方修订 2019 年合同&#xff0c;微软拟弃部分股权换新技术访问权。OpenAI 上周放弃了有争议转…

git工具使用详细教程-------命令行和TortoiseGit图形化

下载 git下载地址&#xff1a;https://git-scm.com/downloads TortoiseGit&#xff08;图形化工具&#xff09;下载地址&#xff1a;https://tortoisegit.org/download/ 认识git结构 工作区&#xff1a;存放代码的地方 暂存区&#xff1a;临时存储&#xff0c;将工作区的代码…

构建RAG混合开发---PythonAI+JavaEE+Vue.js前端的实践

7GB显存如何部署bf16精度的DeepSeek-R1 70B大模型&#xff1f;-CSDN博客 服务容错治理框架resilience4j&sentinel基础应用---微服务的限流/熔断/降级解决方案-CSDN博客 conda管理python环境-CSDN博客 快速搭建对象存储服务 - Minio&#xff0c;并解决临时地址暴露ip、短…

【Java ee初阶】jvm(3)

一、双亲委派机制&#xff08;类加载机制中&#xff0c;最经常考到的问题&#xff09; 类加载的第一个环节中&#xff0c;根据类的全限定类名&#xff08;包名类名&#xff09;找到对应的.class文件的过程。 JVM中进行类加载的操作&#xff0c;需要以来内部的模块“类加载器”…

wps excel将表格输出pdf时所有列在一张纸上

记录&#xff1a;wps excel将表格输出pdf时所有列在一张纸上 1&#xff0c;调整缩放比例&#xff0c;或选择将所有列打印在一页 2&#xff0c;将表格的所有铺满到这套虚线

分布式微服务系统架构第134集:笔记1运维服务器经验,高并发,大数据量系统

加群联系作者vx&#xff1a;xiaoda0423 仓库地址&#xff1a;https://webvueblog.github.io/JavaPlusDoc/ https://1024bat.cn/ https://github.com/webVueBlog/fastapi_plus https://webvueblog.github.io/JavaPlusDoc/ ✅ 一、查看端口是否被占用的常用命令 1️⃣ lsof 命令&…

IS-IS 中间系统到中间系统

前言&#xff1a; 中间系统到中间系统IS-IS&#xff08;Intermediate System to Intermediate System&#xff09;属于内部网关协议IGP&#xff08;Interior Gateway Protocol&#xff09;&#xff0c;用于自治系统内部 IS-IS也是一种链路状态协议&#xff0c;使用最短路径优先…

前端安全:XSS、CSRF 防御与最佳实践

引言 随着互联网应用的普及&#xff0c;前端安全问题日益凸显。作为开发者&#xff0c;了解并防范常见的安全威胁至关重要。本文将深入探讨两种最常见的前端安全威胁&#xff1a;跨站脚本攻击&#xff08;XSS&#xff09;和跨站请求伪造&#xff08;CSRF&#xff09;&#xff…

uniapp 弹窗封装(上、下、左、右、中五个方位)

无脑复制即可&#xff01;&#xff01;&#xff01; <template><view><viewv-if"mask"class"tui-drawer-mask":class"{ tui-drawer-mask_show: visible }":style"{ zIndex: maskZIndex }"tap"handleMaskClick&qu…

Axure制作可视化大屏动态滚动列表教程

在可视化大屏设计中&#xff0c;动态滚动列表是一种常见且实用的展示方式&#xff0c;能够有效地展示大量信息。本文将详细介绍如何使用Axure制作一个动态滚动的列表展示模块。 一、准备工作 打开Axure软件&#xff1a;确保你已经安装并打开了Axure RP软件。创建新项目&#x…

零基础玩转Apache Superset可视化部署

根据官方Quick Start Guide&#xff0c;你可以按照以下步骤进行部署&#xff1a; 1. 确认环境2. 获取代码3. 获取官方最新代码4. 启动服务5. 访问Superset Web界面6. 接入数据源 前提条件&#xff1a; dockerdocker compose 1. 确认环境 安装Docker和Docker Compose 确保你…

服务器数据恢复—XFS文件系统分区消失的数据恢复案例

服务器数据恢复环境&故障&#xff1a; 服务器上有一组由raid卡组建的raid5磁盘阵列。上层安装linux才做系统&#xff0c;采用XFS文件系统&#xff0c;划分了3个分区。 管理员将服务器的操作系统重装后&#xff0c;发现服务器上的分区发生了改变&#xff1a;一个分区消失&am…

2025/5/18

继续研究一下大佬的RAG项目。开始我的碎碎念。 RAG可以分成两部分&#xff1a;一个是问答&#xff0c;一个是数据处理。 问答是人提问&#xff0c;然后查数据库&#xff0c;把查的东西用大模型组织成人话&#xff0c;回答人的提问。 数据处理是把当下知识库里的东西&#xf…