ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Effective C++ 阅读笔记之Chapter5

2021-10-27 19:59:16  阅读:173  来源: 互联网

标签:... const 定义 Effective Chapter5 C++ inline class 函数


前言

大家好,我是雨墨,我深知好记性不如烂笔头的道理,所以在阅读的时候都尽量写读书笔记,方便日后复习,当然笔记并不能代替书籍上的内容。希望我的笔记也能帮助到大家,如果我的笔记有什么问题,欢迎大家给小老弟纠错~

条款二十六总结

延后变量的定义,且最好在定义的时候给它初始值实参,否则你应该尽可能延后定义。

string encryptPassword(const string& password) {
    ...
    string encrypted(password);		// 这样做就很棒!
    
    ...
    return encrypted;
}

如果遇到循环:如果变量是 class 对象的时候,你必须要考虑定义在循环外和定义在循环内哪一种成本更高,包含构造成本、析构成本、赋值成本。然后选择成本较低的那一种。

// 方法 A
Widget w;
for (int i = 0; i < n; ++i) {
    w = 取决于 i 的某个值;
    ...
}

// 方法 B
for (int i = 0; i < n; ++i) {
    Wiget w(取决于 i 的某个值);
    ...
}

除非你知道赋值成本比 “构造+析构” 低,或是你正在处理高度敏感的部分,否则应当使用方法 B。我的理解是:方法 B 延迟了 w 的定义,且在定义的时候给了 w 初始值。

条款二十七总结

  • 尽量少做转型动作,如果需要做转型,也尽可能使用新式转型。
  • 如果转型是必要的,试着将其隐藏在函数里头。

书上 p117 - p122 的例子不错,复习时可以再看看。

条款二十八总结

  • 介绍一下 handles ,references、ptr、iterator,都是所谓的 handles (号码牌);

  • 如非必要,应该避免返回一个 handle 指向对象内部,不然会降低对象的封装性,并且,返回一个 handle 指向临时对象有时还可能造成 handle 空悬的情况。一一举例说明

    class Point {
        ...
    };
    class RectData {
        ...
    };
    
    class Rectangle {
    public:
        ...
        Point& upper_left() const { return m_p_data->ulhc; }	// error ! 
        Point& lower_right() const { return m_p_data->lrhc; } // error !
    private:
        shared_ptr<RectData> m_p_data;
    };
    
    

    上述代码存在错误的原因:

    1. upper_left 被声明为了 const 函数,但返回的是 Point& 又存在改变 m_pdata->ulhc 的风险,同理lower_right 也是。
    2. 原本声明 m_pdata 就是不想让用户修改数据,但是通过 upper_left 就可以做到,这降低了对象的封装性!

    因此,对于对象的内部(包括内部对象以及不被公开使用的函数),避免返回他们的 handle ,不然他们的访问级别就会出现改变。

class GUIObject { ... };
const Rectangle
bounding_box (const GUIObject& ob);

// user action
const Point* p_upper_left = &(bounding_box(*pgo).upper_left());

上述代码可能造成 dangling handles :

最后一条语句结束之后,bounding_box() 的返回值由于是临时对象,生命周期已经到了,被销毁,然后留下孤零零的 p_upper_left 指向一个不存在的对象,造成 p_upper_left 空悬。

条款二十九总结

  • 在任何情况下,你都应该为你的代码拥有安全性保障。出了防止资源泄露,你还需要提供 基本承诺、强烈保证、不抛掷保证。
  • 有一个经典的策略可以提供强烈保证,copy and swap ,即拷贝一个副本做改变,如果没有抛出异常,那么就将其拷贝给原来的对象,应该了解它。
  • 并不是所有的函数都能提供强烈保证,如果无法提供强烈保证,你需要提供基本保证。

这一章节涉及的知识不是那么容易搞明白,遇到问题多翻阅,配合 C++ Primer 的异常处理进行阅读。

条款三十总结

  • 不要过度热衷于使用 inline ,因为过度使用 inline 可能会使得程序体积过大,亦或是导致换页,换页意味着第一次访问肯定是不命中的,造成指令cache 的命中率降低。
  • 记住 inline 只是对编译器的一种申请,它不一定会让你这么做。
  • inlining 在大多数 C++ 程序中是编译器行为,template 也是,因此要将其申明在头文件中。
  • 拥有太多的循环或递归的函数编译器会拒绝让其申请为 inline 。
  • 对于 virtual 函数,直到运行时才知道它是哪个版本,更不能申请为 inline 了。
  • 编译器通常不会将函数指针申明为 inline 。
  • 构造函数和析构函数是糟糕的 inlining 候选人,看起来他们函数体里边什么都没有,但实际上编译器会在编译器安插许多异常处理的代码到其函数体内,使其尤为庞大。
  • 程序库设计者也应该评估能否将函数声明为 inline ,这会造成很大的效率差别,但我不认为我能到达那个水平…

作为开发人员应该牢记上述的建议,不要热衷使用 inline ,而应该寻找程序中 20% 的地方使用 inline 为其瘦身。

条款三十一总结

将文件之间的编译依存关系降至最低,这样能保证你不会出现修改一下某个成分就出现重新编译和连接的结果。

How?

  • 以 ”声明的依存性“ 代替 ”定义的依存性“ 。

    • 能使用 object references 或 object pointers 完成的任务不要使用 object ,因为前者不需要定义,只需要声明式,后者需要给出定义式;

    • 尽量以 class 声明代替 class 定义。一个函数用到了一个 class ,并不需要这个 class 的定义,所以初步可以写成

      #include <string>
      #include <memory>
      
      class PersonImpl;	// 对应第二条
      class Date;
      class Address;
      
      class Person {
      public:
      	Person(const string& name, const Date& birthday, const Address& addr);	// 这里对应第一条
          string name() const;
          string birthda() const;
          string address() const;
          ...
      private:
          shared_ptr<PersonImpl> pImpl;
      };
      
  • 但这是不够的,如果能够将 ”函数声明所在“ 的头文件转移到 ”内涵函数调用“ 的客户文件,便可将 “并非真正必要的类型定义” 于客户端之间的编译依存性去除掉。

    • 为声明式和定义式提供不同的文件。参照标准库的声明头文件定义,在头文件名加上 fwd ,这样的好处是:不用额外声明,直接 #include 头文件即可,就不用在多个文件中声明一样的东西。

      #include "datafwd.h"
      Date today();	// 没有在本文件中声明 class Date ,而是 #include "datafwd.h"
      

基于此思想的两种做法是

  • Handle classes
  • Interface classes

具体是如何实现的书上有明确的讲述,多看多思考。

**这里仍然存在疑问:这两种方式是如何降低编译依存关系的?**希望有一天能回来解答上!

参考书籍:
《Effective C++》

标签:...,const,定义,Effective,Chapter5,C++,inline,class,函数
来源: https://blog.csdn.net/qq_51387669/article/details/121000514

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有