《EffectiveC++》读书笔记(4):设计与声明

C语言与CPP编程 2023-08-02 08:30

击上方“C语言与CPP编程”,选择“关注/置顶/星标公众号

干货福利,第一时间送达!

最近有小伙伴说没有收到当天的文章推送,这是因为微信改了推送机制,有一部分小伙伴刷不到当天的文章,一些比较实用的知识和信息,错过了就是错过了,建议大家加个星标⭐️,就能第一时间收到推送。

小伙伴们大家好,我是飞宇。

前段时间润去美国的师兄开了一门C/C++的课程,友情帮忙宣传一下,感兴趣的可以看看。

今天继续更新《Effective C++》和《C++并发编程实战的读书笔记,下面是已经更新过的内容:

《C++并发编程实战》读书笔记(1):并发、线程管控

《C++并发编程实战》读书笔记(2):并发操作的同步

《C++并发编程实战》读书笔记(3):内存模型和原子操作

《C++并发编程实战》读书笔记(4):设计并发数据结构

《Effective C++》读书笔记(1):让自己习惯C++

《Effective C++》读书笔记(2):构造/析构/赋值运算

《Effective C++》读书笔记(3):资源管理

本文包括第6章设计基于锁的并发数据结构与第7章设计无锁数据结构,后者实在有些烧脑了。此外,发现吴天明版的中译本有太多太离谱的翻译错误了,还得是中英对照才行:


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

    好的接口容易被正确使用,不易被误用;应使自己的所有接口努力达成这一点。

    “容易被正确使用”的办法包括:

    1、接口的一致性。例如STL的容器几乎都有类似的接口。

    2、与内置类型行为类似。例如对于int类型来说a*b=c是非法的,那么自己定义的operator*也应该避免a*b=c的操作。

    “不易被误用”的方法包括:

     1、建立新类型。例如对于以int类型的年、月、日作为参数的接口来说,用户很可能搞混顺序(不同国家年月日的常用顺序不一),那么可以建立年类、月类、日类作为参数类型。

   2、限制类型上的操作。例如令返回值为const,即可阻止用户写出“a*b=c”的代码。

    3、限制对象值。例如参数像月份这样取值有限,即可使用枚举类或者预先定义一系列函数返回所有月份。

    4、消除用户的资源管理责任。例如条款13中提过一个工厂方法:

Widget* create_Widget() { ... }

如果只是返回一个裸指针,那么删除指针释放资源的责任就落在用户身上,而这常常会带来问题;如果把返回值改为shared_ptr,那么自动释放资源。

    shared_ptr还有个性质是会使用每个指针专属的删除器。如果对象在一个DLL中被new创建而在另一个DLL内被delete,会引起运行期错误;而shared_ptr使用的删除器来自创建时所在的DLL,不存在上述问题。


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

    当定义了一个新class,也就定义了一个新type。在定义一个新type前考虑以下问题:

    新type的对象应该如何被创建和销毁?

    对象的初始化和对象的赋值该有什么样的差别?

    新type的对象如果被passed by value意味着什么?

    什么是新type的合法值?

    你的新type需要配合某些继承图系吗?

    你的新type需要什么样的转换?

    什么样的操作符和函数对此新type而言是合理的?

    什么样的标准函数应该驳回?

    谁该取用新type的成员?

    什么是新type的未声明接口?

    你的新type有多么一般化?

    你真的需要一个新type吗?



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

    默认情况下C++以by value方式传参。这意味着函数参数都是由实参拷贝构造而来,调用端获得的也是函数返回值拷贝构造而来(不过有各种优化方式),多次拷贝的成本非常大。

    C++中引用通常以指针来实现,传引用的成本相当低。因此,绝大多数情况下,用pass-by-reference-to-const替换pass-by-value更加高效。

    此外,如果采用pass-by-value,如果误将派生类对象传给基类参数,那么派生类成员将被截断,仅留下基类成员;使用pass-by-reference-to-const即可避免这样的切割问题。

    以上规则并不适用于内置类型以及STL的迭代器和函数对象,因为它们本质上很小,pass-by-value更适当。



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

    虽然条款20中介绍了对于函数参数而言pass-by-reference-to-const相比pass-by-value的优势,但是对于函数返回值而言情况又不一样了。

    当要返回的对象是一个局部栈对象时,函数退出后该对象就被销毁,无法通过指针或引用访问。因此函数返回值不能是指针或引用,必须是值传递。

    当要返回的对象是函数内分配的堆对象时,如果返回的是堆对象的引用,那么函数退出后指针无法被删除,该堆对象无法被回收。因此需要返回堆对象的指针。

const Widget& f(){  Widget* p = new Widget();  return *p;}


    当返回的对象是局部静态变量的指针或引用时,如果程序的逻辑可能同时需要多个这样的对象,那么显然会出错:

const Rational& operator*(const Rational& lhs, const Rational& rhs){  static Rational result;  ...  return result;}
Rational a,b,c,d;...if((a*b)==(c*d)) //此时等号两边是同一个对象   


    正确的做法是:对于返回值而言,该用值传递是就用值传递

const Rational operator*(const Rational& lhs, const Rational& rhs);


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

    将成员变量声明为private有各种好处:

    1、客户访问数据的一致性。客户只需记住用访问器函数来得到数据,无需考虑哪些是成员函数、那些是成员变量。

    2、可细微划分访问控制。public成员全都可读可写,而private成员可以通过访问器、修改器的不同设置来控制读写权限。

    3、为所有可能的实现提供弹性。private成员完全封装,日后完全可以在不影响用户使用的前提下被修改或替换。

    protected并不比public更具封装性。假设取消一个已存在的protected/ic成员变量,那么所有派生类中使用到它的都需相应调整;而取消一个private成员变量则无需这样。



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

    越多成员被封装,则越少用户能访问它们,则修改它们时弹性就越大。而对于成员变量来说(首先应该是private),能访问它的函数越多,则其封装性越低。

    那么,如果在成员函数与非成员/非友元函数之间抉择,并且两者提供相同的技能,那么非成员/非友元函数能访问的成员变量更少,封装性更强。

class WebBrowser{public:  void clear_cache();  void clear_history();  void clear_all{    clear_cache();    clear_history;  }};
void clear_webbrowser(WebBrowser& wb){  wb.clear_cache();  wb.clear_history();}

    C++中比较自然的做法是选择clear_webbrowser而非WebBrowser::clear_all,并将其置于WebBrowser的命名空间中。




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

    如果需要让某函数的所有参数都进行类型转换,包括this指针所指的参数,那么该函数必须是non-member的。

    虽然让类支持隐式类型转换通常很糟糕,但有个例外是建立数值类型时:

class Rational{public:  //参数分别为有理数的分子与分母  Rational(int numerator = 0,int denominator = 1);  int numerator() const;  int denominator() const;  const Rational operator*(const Rational& rhs) const;}


    当operator*是成员函数时,无法解决这样的代码:

Rational r1,r2;...r1 = 2 * r2;//实质上等于 r1 = 2.operator*(r2)


    对于有理数类的乘法,如果要支持字面量隐式转换为有理数对象,那么该类的operator*的所有参数都可能需要类型转换。因此成员函数无法解决这个问题,必须转为非成员函数:

const Rational operator*(const Rational& lhs,const Rational& rhs);


条款25、考虑写出一个不抛异常的swap函数

    swap函数目前已是异常安全性编程的脊柱(copy and swap写法)。

    如果对于你的类/模板类来说,swap的默认实现的效率可接受,那么无需额外做什么;而如果默认实现的效率不足,通常源于类为了二进制兼容性使用了pimpl技法,就需要实现一个确保不抛出异常的swap:

    1、首先,提供一个public的swap成员函数,让它高效地置换两个对象。

   2、在类/模板类所在的命名空间提供一个non-member的swap,调用swap成员函数。

    3、对于类(而非模板类),还需特化std::swap,调用swap成员函数。

    4、真正使用swap时先声明using std::swap,再直接使用swap,让编译器寻找最合适的swap实现版本。

namespace WidgetStuff{  // WidgetImpl对象非常大  class WidgetImpl { ... };   // Widget是上面的pimpl类,用指针指向Widget  class Widget{  public:    Widget& operator=(const Widget& rhs){      *(p_impl)=*(rhs.p_impl);    }  //swap时只需交换指针,所以默认实现效率不足    void swap(Widget& other){      using std::swap;      swap(p_impl, other.p_impl);      }  private:    WidgetImpl* p_impl;  }    // 同一命名空间下提供一个non-member的swap   void swap(Widget& lhs, Widget& rhs){    lhs.swap(rhs);  }
}//std命名空间内提供特化版本的swapnamespace std{  template<>  void swap(Widget& lhs, Widget& rhs){    lhs.swap(rhs);  }}

EOF

你好,我是飞宇,本硕均于某中流985 CS就读,先后于百度搜索以及字节跳动电商等部门担任Linux C/C++后端研发工程师。

同时,我也是知乎博主@韩飞宇,日常分享C/C++、计算机学习经验、工作体会,欢迎点击此处查看我以前的学习笔记&经验&分享的资源。

我组建了一些社群一起交流,群里有大牛也有小白,如果你有意可以一起进群交流。

欢迎你添加我的微信,我拉你进技术交流群。此外,我也会经常在微信上分享一些计算机学习经验以及工作体验,还有一些内推机会

加个微信,打开另一扇窗

C语言与CPP编程 C语言/C++开发,C语言/C++基础知识,C语言/C++学习路线,C语言/C++进阶,数据结构;算法;python;计算机基础等
评论
  • 一个易用且轻量化的UI可以大大提高用户的使用效率和满意度——通过快速启动、直观操作和及时反馈,帮助用户快速上手并高效完成任务;轻量化设计则可以减少资源占用,提升启动和运行速度,增强产品竞争力。LVGL(Light and Versatile Graphics Library)是一个免费开源的图形库,专为嵌入式系统设计。它以轻量级、高效和易于使用而著称,支持多种屏幕分辨率和硬件配置,并提供了丰富的GUI组件,能够帮助开发者轻松构建出美观且功能强大的用户界面。近期,飞凌嵌入式为基于NXP i.MX9
    飞凌嵌入式 2025-01-16 13:15 158浏览
  • 日前,商务部等部门办公厅印发《手机、平板、智能手表(手环)购新补贴实施方案》明确,个人消费者购买手机、平板、智能手表(手环)3类数码产品(单件销售价格不超过6000元),可享受购新补贴。每人每类可补贴1件,每件补贴比例为减去生产、流通环节及移动运营商所有优惠后最终销售价格的15%,每件最高不超过500元。目前,京东已经做好了承接手机、平板等数码产品国补优惠的落地准备工作,未来随着各省市关于手机、平板等品类的国补开启,京东将第一时间率先上线,满足消费者的换新升级需求。为保障国补的真实有效发放,基于
    华尔街科技眼 2025-01-17 10:44 98浏览
  • 电竞鼠标应用环境与客户需求电竞行业近年来发展迅速,「鼠标延迟」已成为决定游戏体验与比赛结果的关键因素。从技术角度来看,传统鼠标的延迟大约为20毫秒,入门级电竞鼠标通常为5毫秒,而高阶电竞鼠标的延迟可降低至仅2毫秒。这些差异看似微小,但在竞技激烈的游戏中,尤其在对反应和速度要求极高的场景中,每一毫秒的优化都可能带来致胜的优势。电竞比赛的普及促使玩家更加渴望降低鼠标延迟以提升竞技表现。他们希望通过精确的测试,了解不同操作系统与设定对延迟的具体影响,并寻求最佳配置方案来获得竞技优势。这样的需求推动市场
    百佳泰测试实验室 2025-01-16 15:45 197浏览
  • 全球领先的光学解决方案供应商艾迈斯欧司朗(SIX:AMS)近日宣布,与汽车技术领先者法雷奥合作,采用创新的开放系统协议(OSP)技术,旨在改变汽车内饰照明方式,革新汽车行业座舱照明理念。结合艾迈斯欧司朗开创性的OSIRE® E3731i智能LED和法雷奥的动态环境照明系统,两家公司将为车辆内饰设计和功能设立一套全新标准。汽车内饰照明的作用日益凸显,座舱设计的主流趋势应满足终端用户的需求:即易于使用、个性化,并能提供符合用户生活方式的清晰信息。因此,动态环境照明带来了众多新机遇。智能LED的应用已
    艾迈斯欧司朗 2025-01-15 19:00 74浏览
  • 实用性高值得收藏!! (时源芯微)时源专注于EMC整改与服务,配备完整器件 TVS全称Transient Voltage Suppre,亦称TVS管、瞬态抑制二极管等,有单向和双向之分。单向TVS 一般应用于直流供电电路,双向TVS 应用于电压交变的电路。在直流电路的应用中,TVS被并联接入电路中。在电路处于正常运行状态时,TVS会保持截止状态,从而不对电路的正常工作产生任何影响。然而,一旦电路中出现异常的过电压,并且这个电压达到TVS的击穿阈值时,TVS的状态就会
    时源芯微 2025-01-16 14:23 130浏览
  • 故障现象 一辆2007款法拉利599 GTB车,搭载6.0 L V12自然吸气发动机(图1),累计行驶里程约为6万km。该车因发动机故障灯异常点亮进厂检修。 图1 发动机的布置 故障诊断接车后试车,发动机怠速轻微抖动,发动机故障灯长亮。用故障检测仪检测,发现发动机控制单元(NCM)中存储有故障代码“P0300 多缸失火”“P0309 气缸9失火”“P0307 气缸7失火”,初步判断发动机存在失火故障。考虑到该车使用年数较长,决定先使用虹科Pico汽车示波器进行相对压缩测试,以
    虹科Pico汽车示波器 2025-01-15 17:30 90浏览
  • 百佳泰特为您整理2025年1月各大Logo的最新规格信息,本月有更新信息的logo有HDMI、Wi-Fi、Bluetooth、DisplayHDR、ClearMR、Intel EVO。HDMI®▶ 2025年1月6日,HDMI Forum, Inc. 宣布即将发布HDMI规范2.2版本。新规范将支持更高的分辨率和刷新率,并提供更多高质量选项。更快的96Gbps 带宽可满足数据密集型沉浸式和虚拟应用对传输的要求,如 AR/VR/MR、空间现实和光场显示,以及各种商业应用,如大型数字标牌、医疗成像和
    百佳泰测试实验室 2025-01-16 15:41 142浏览
  • 80,000人到访的国际大展上,艾迈斯欧司朗有哪些亮点?感未来,光无限。近日,在慕尼黑electronica 2024现场,ams OSRAM通过多款创新DEMO展示,以及数场前瞻洞察分享,全面展示自身融合传感器、发射器及集成电路技术,精准捕捉并呈现环境信息的卓越能力。同时,ams OSRAM通过展会期间与客户、用户等行业人士,以及媒体朋友的深度交流,向业界传达其以光电技术为笔、以创新为墨,书写智能未来的深度思考。electronica 2024electronica 2024构建了一个高度国际
    艾迈斯欧司朗 2025-01-16 20:45 109浏览
  • 随着智慧科技的快速发展,智能显示器的生态圈应用变得越来越丰富多元,智能显示器不仅仅是传统的显示设备,透过结合人工智能(AI)和语音助理,它还可以成为家庭、办公室和商业环境中的核心互动接口。提供多元且个性化的服务,如智能家居控制、影音串流拨放、实时信息显示等,极大提升了使用体验。此外,智能家居系统的整合能力也不容小觑,透过智能装置之间的无缝连接,形成了强大的多元应用生态圈。企业也利用智能显示器进行会议展示和多方远程合作,大大提高效率和互动性。Smart Display Ecosystem示意图,作
    百佳泰测试实验室 2025-01-16 15:37 148浏览
  • 近期,智能家居领域Matter标准的制定者,全球最具影响力的科技联盟之一,连接标准联盟(Connectivity Standards Alliance,简称CSA)“利好”频出,不仅为智能家居领域的设备制造商们提供了更为快速便捷的Matter认证流程,而且苹果、三星与谷歌等智能家居平台厂商都表示会接纳CSA的Matter认证体系,并计划将其整合至各自的“Works with”项目中。那么,在本轮“利好”背景下,智能家居的设备制造商们该如何捉住机会,“掘金”万亿市场呢?重认证快通道计划,为家居设备
    华普微HOPERF 2025-01-16 10:22 157浏览
  • 晶台光耦KL817和KL3053在小家电产品(如微波炉等)辅助电源中的广泛应用。具备小功率、高性能、高度集成以及低待机功耗的特点,同时支持宽输入电压范围。▲光耦在实物应用中的产品图其一次侧集成了交流电压过零检测与信号输出功能,该功能产生的过零信号可用于精确控制继电器、可控硅等器件的过零开关动作,从而有效减小开关应力,显著提升器件的使用寿命。通过高度的集成化和先进的控制技术,该电源大幅减少了所需的外围器件数量,不仅降低了系统成本和体积,还进一步增强了整体的可靠性。▲电路示意图该电路的过零检测信号由
    晶台光耦 2025-01-16 10:12 89浏览
  • 随着消费者对汽车驾乘体验的要求不断攀升,汽车照明系统作为确保道路安全、提升驾驶体验以及实现车辆与环境交互的重要组成,日益受到业界的高度重视。近日,2024 DVN(上海)国际汽车照明研讨会圆满落幕。作为照明与传感创新的全球领导者,艾迈斯欧司朗受邀参与主题演讲,并现场展示了其多项前沿技术。本届研讨会汇聚来自全球各地400余名汽车、照明、光源及Tier 2供应商的专业人士及专家共聚一堂。在研讨会第一环节中,艾迈斯欧司朗系统解决方案工程副总裁 Joachim Reill以深厚的专业素养,主持该环节多位
    艾迈斯欧司朗 2025-01-16 20:51 90浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦