非书评-内容笔记简述以及引申

王很水
2018-07-05 19:31:40

泛型程序设计与c++标准库

item1流理解cin/cout实现一个echo理解工程设计原则-即尽可能的提高扩充-尽量提高封装

item2理解std::remove原理(<algorithm>) 由find(_if)实现,++i != last; 以及erase-remove惯用法

item3状态谓词带来的问题stateful-predicate没有好的解决方案,用上智能指针,共享谓词状态。还是考虑需求为啥要这样实现吧。

item4 扩充模板用 traits还是继承

  • 继承,约束接口,约束类(imperfectc++也讲过,就是函数指针赋值,让编译器帮你检查)
  • SFINAE来匹配接口指针
  • 工厂类?将约束构造放在类内部,客户端类作为模板参数,来(内部特化)匹配出相应的构造
  • traits 高扩展,(如果嫌逐个类写traits麻烦也可以参考AA的书中的解决办法)
  • 为了处理模板中的分类而是用继承不足以成为使用继承的理由。

item5typename以及如何使用

  • 名字查找,模板实例化才知道,所以不能找到的符号会报错,所以需要typename暗示出来。
  • typedef hell

item6容器,指针,和不是容器的容器

  • 原生指针和解引用迭代器有时候很有用,但是好考虑是否有效
  • fuckvector<bool> //bitvector,用vector<char> vector<int> deque<bool>

item7 使用vector和deque

  • 顺序容器优于数组,默认用vector ,经常在头尾插入删除就用deque
  • deque分页组织,在体积增长上优于vector,vector push_back要用reverse惯用法,否则低效(反复扩大->挪动)另外,reserve不会缩小空间(shrink_to_fit in c++11)可以用swap trick(shrink_to_fit应该也是这样实现的)
  • swap惯用法 包括上面的场景与clear操作(swap 一个空对象更trick一些,这点在effective stl 中也有提到,不过c++11应该优化了clear)

item8 set 与map

  • 关联容器,作为key相对位置不能变,key不能被强行改,否则内部的数据结构遍历就会失去控制(map就是const key)
  • set可以看成 map<Key,void>
  • 你必须知道你在做什么(如果你用const_cast强行改的话)

item9 f(a++) f(a);a++ 代码中的微小差别会带来影响吗

  • 多种语义 ,a 是类,那么a的operator++(int)实现是怎样的,f可能是宏,也可能是函数传引用参数或指针
  • 接着上面,第二种写法,考虑a 是迭代器,f是erase,迭代器失效就不能调用operator++(int)了,但第一种写法却是对的
  • 总而言之,两种写法都要小心,你必须知道你在做什么

item10 模板特殊化与重载

  • 显式特化 偏特化(只有类模板可以)
  • 函数模板特化,函数重载引入的歧义性

item11 熟悉泛型设计的例子

优化与性能

item12 inline

  • 你到底想优化什么,内联如果不是热点,反而适得其反使得提及增大cache 加大反而降低速度
  • profiler 说了算,优化原则,别用

item13~item16 缓冲优化 string实现 以及COW写时复制

  • 最佳缓冲区增长策略 logn
  • COW 一个应用,Linuxfork,引用计数,所谓的浅拷贝和深拷贝不过是返回*this 还是new(*this)
  • COW带来的问题,operator[](不能共享就new一个)(禁止拷贝也行),迭代器,线程不安全(这个和shared_ptr不是线程安全一个道理)(加锁性能损失也很大)
  • 新版std::sring 转而采用SSO,需要理解原理

异常安全

item17-19 构造函数失败 ->处理异常 ->未捕获异常

  • 对象生命期,如果构造函数异常了会怎样(初始化列表也可以加上try-block(就是有点难看)(就是function-try-block),且必须抛异常,所以尽量放在函数内部局部的处理(普通try-block))
  • 接上,只要任何一个基类或成员子对象构造失败,整体就构造失败,改变设计转向pimpl,而不是继承->还是耦合与内聚的问题
  • try-block 也不建议用在析构中,析构抛异常是傻逼行为(c++11 编译器会警告,noexcept)
  • 注意构造函数的异常规范,能用RAII就用RAII吧。
  • 接上,假设傻逼了,析构抛异常不处理,用if-std::uncaught_exception分支处理,会使语义复杂,也很傻逼。还不如用个try-clean_func-catch来处理。

item20-21 管理指针 ->auto_ptr?

  • 参数求值完成在函数调用前,考虑函数调用中的异常安全问题,比如new多个参数?参数可能构造失败
  • 试图使用auto_ptr解决问题,直接把参数改成auto_ptr 也是不行的,但有个临时方案,再封装一层函数模板返回auto_ptr临时对象,临时对象的生命周期只有一行,如果失败前面的参数资源也不会泄露
  • 或者就不要这么写,资源由智能指针托管就行了,别再入参里new

item22 异常安全与类的设计->如何写个operator=()

  • 假设类中有类成员(多个),考虑 class& operator=(class&)如何才能更安全 (万金油 pimpl)
  • 保证swap 异常安全,用swap( 上智能指针)

item23 异常安全与类的设计->继承带来的影响

  • 尽量不用继承来描述is-implemented-in-terms-of,考虑继承下的对象怎么实现operator=() (过于耦合)

继承与多态

item24-28 为什么要使用多继承 ->模拟多继承 ->纯虚函数 ->受控的多态

  • 为什么要使用多继承,不是接口抽象类就不要瞎继承了
  • 模拟多继承,->组合,像多继承那样安排就好了。
  • 切割问题,引入中间类避免
  • 纯虚函数,纯虚函数也可以提供默认行为,由派生类显式调用更明显些。
  • 接上,默认行为 + 装饰器模式,提供部分行为
  • 控制多态 ->友元函数。

内存及资源管理

item29-31 auto_ptr带来的问题 c++11 开始auto_ptr被废弃

  • auto_ptr 不能托管数组 数组new 比较坑爹 改进方案 抄一个auto_array, 写个adapter封装数组,不要用数组
  • auto_ptr拷贝构造的问题,delete两次(c++11 用unique_ptr取代,禁止拷贝)
  • 实现一个value_ptr(有点像加强版unique_ptr)

自由函数与宏

item32 递归声明

  • 函数指针如何返回自身? ->代理类封一层函数指针,绕出来,而不是void *硬刚,无开销,就是不能模板通用

item33 模拟嵌套函数

  • 嵌套类和局部类。实现operator()()(c++11 有lambda)

item34-35 宏带来的问题

  • 安全性问题 const替换
  • head-file guard 这个无法取代
  • 括号
  • 本质是名字替换。所以可能造成冲突,宏机制各个编译器实现有差别

杂项 MISC

item36 初始化 了解构造初始化拷贝初始化语义 (《深入了解c++对象模型》)

item37 前置声明消除编译期依赖 <iosfwd> 以及,不要把typedef当成类了,class string这种

item38 typedef

  • 偷懒 (所以说在c中,不值得用typedef来简写struct)
  • traits

item39-40 namespace

  • 不要在头文件中使用using 污染名字空间
  • using与声明顺序,不要放在#include前

书后是一个多线程 cow string实现(加锁),以及性能测试

0
0

查看更多豆瓣高分好书

回应(0)

添加回应

推荐More Exceptional C++中文版的豆列

了解更多图书信息

豆瓣
免费下载 iOS / Android 版客户端