代码大全

距离上次什么时候写博客已经记不清了, 看了眼GitHub备份记录 已经25天了. 这25天我咕了吗? 咕是不可能咕的. 这段时间我终于做出了第一个UE4比较完善的联机游戏.
学习了更多的muduo自己的mongo也更加完善. 只看书写博客不写代码可不行.

技术类书籍慢慢开始看了, mongo写的时间不短了. 代码大全听说是神书? 来粗读看看吧

第?部分

第六章 可以工作的类

使用ADT 可以实现隐藏细节, 改动不会影响到整个程序.

这点感受还是有些的. 前两天自己写VPN(目前项目暂停了)的时候, 有个Buffer类, Buffer类的核心是libevent的evbuff, 我直接使用Get方法Get到这个evbuff的指针, 然后在外部进行操作.
起初这样只是图简单吧, 也想到了这样会写出烂代码. 后面改动核心evbuff的时候, 发现太麻烦了, 最终改成了几个简单的接口 Append Clear等, 对外隐藏了内部是什么缓冲结构

has a —- 组合 包含
is a —- 集成 epoll(select) is a mutiplexing

只有一个实例的类是值得怀疑的, 同样只有一个派生类的基类也是值得怀疑的

拷贝对象优先使用深拷贝

创建类的原因

  • 为现实世界中的对象建模
  • 为抽象的对象建模 形状类是抽象的 不过圆 正方形等都是真实存在的
  • 降低复杂度 一个类创建结束后, 你就可以忘掉其中的细节 使用接口即可
  • 隔离复杂度
  • 隐藏实现细节 限制变动的影响范围 隐藏全局数据
  • 让参数传递更加舒畅 成员变量
  • 复用代码

第七章 高质量的子程序

创建子程序的正当理由

  • 降低复杂度
    一个子程序编写完毕后, 应该可以忘记其中的细节
  • 引入中间,易懂的抽象
    避免代码重复 从大块的代码中抽取子程序
  • 隐藏顺序 如果某两行代码有特定的执行顺序, 可以考虑抽取出来. 感觉这里可以推广到Mutex lock后忘记unlock 或者 Buffer中读取数据后 忘记移动指针?
  • 提高可移植性 这点看项目了

似乎过于简单没有必要写成子程序, 当然也要看情况了

  • 这里我感觉最深的还是 两行或者三行经常调用的程序, 如果重复写多次 最终告知你需要修改的时候 那可真是灾难性的消息. 实例的话: 增加参数校验等等

准确的使用对仗词

add remove
begin end
create destory
next previous
start stop

如何使用子程序参数

  • 按照输入-修改-输出的顺序排列参数
  • 如果几个子程序都是用了类似的一些参数, 应该让这些参数的排列顺序一致
  • 使用所有的参数, 删去未使用到的参数
  • 不要把子程序的参数用做工作变量

设置函数的返回值

  • 检查所有可能的返回路径, 在函数开头设置默认返回 一个不错的选择(muduo中见到了)
  • 老生常谈的不要返回局部对象的引用或者指针

少使用宏吧 inline和typedef 不香吗, 不是肉包子也是好吃的素包子了

第八章 防御式编程

防御式编程并不是说让你在编程时保持 “防备批评或攻击” 的态度

子程序不应该因为传入错误数据而被破坏

  • 检查所有源自外部数据的值
  • 检查子程序所有输入参数的值
  • 决定如何处理错误的输入数据

使用错误处理代码来处理与其发生的状况, 使用断言来处理绝不应该发生的状况

错误处理技术 其他感觉… 用不到吧 现在不记录了

  • 返回中立值 最简单的方法, 继续执行操作并简单的返回一个没有危害的数值. 数值计算-返回0 字符串返回空串 指针返回空指针
  • 日志打印
  • 关闭程序

隔离程序
两块相对独立的代码块 在交互函数见进行参数校验 过滤掉一个模块传来的非法参数

辅助调试的代码…..
我现在就遇到一个bug 还不知道怎么修改 与多线程有关的问题 排查真难-2020年5月18日13:11:43
2020年6月18日23:50:44 排查掉了 今天看到了这段话 补充上吧

决定产品最终发布的时候应该保留多少防御内容
防御内容越多消耗的性能越多

第九章 伪代码的编程过程

原则

  • 用类似英语的句子来准确描述特定的操作
  • 便面使用目标编程语言中的特定语法元素
  • 在本意的层面上编写伪代码. 用伪代码描述解决问题的方法意图, 而不是去写如何用目标语言实现这个方法
  • 在一个足够低的层次上编写伪代码, 以便近乎自动的生成代码, 如果层次过高则会隐藏细节问题
  1. 定义子程序要解决的问题
  • 子程序将要隐藏的信息
  • 传给子程序的各项输入, 得到的输出
  • 调用子程序前确保相关前条件成立. 输入数据的范围正确 流已经初始化 文件已经打开或关闭
  • 在子程序将控制权交回调用方程序之前, 确保其后条件成立. 多线程问题居多
  1. 为子程序命名
  2. 决定如何测试子程序
  3. 在标准库中搜寻可用的功能
  4. 考虑错误处理和效率问题

第三部分 变量variables

第十章 使用变量的一般事项

这本书还教你做人… 分数不可能很高 因为有的概念是杜撰的!!
(请读第33章 个人性格 诚实一节)

位图
B-树


文字量
查找表
引用完整性

共用体
变体

  • 在声明的时候就进行初始化
  • 在理想的情况下, 在靠近第一次使用变量的位置声明和定义变量
  • 多多使用const 吧
  • 注意计数器和累加器. 这里很久前遇到一个坑 无符号自减可能会下溢
  • 构造函数中进行初始化
  • 检查是否需要重新初始化
  • 检查输入的合法性
  • 初始化指针建议初始化为 0, 一旦你看到为0的指针越界就知道是没有赋值

第十一章 变量名的力量

  1. 为循环下标 临时变量命名
  2. bool变量
    done->事情已经完成
    error->有错误发生
    found->找到
    success/ok ->某操作已经成功 不是很具体
    Is前缀可以用在模糊不清的词前, 不过这样也会导致最终表达模糊不清
  3. 标识全局变量 使用 g_ 前缀
  4. 标识类型声明 T 前缀
  5. 避免在名字中使用1 2 后缀file_1 file_2

第十二章 基本数据类型

  1. 避免使用神秘数值 突然出现某个数值 这样一方面不便于修改所有值 一方面防止忘记数值含义
  2. 除零 的发生
  3. 防止溢出 这里最常见的就是循环体中了 更尤其是unsigned变量自减的时候
  4. 防范数组越界
  5. C风格字符串的长度声明为 CONSTANT+1, CONSTANT是长度. 防止到时候你分不清长度是该+1还是-1还是就是本身

if(chosen_color = 1)if(chose_color = Color_Red)后者枚举的使用更清楚.
枚举示例

enum Color
{
COLOR_RED,
COLOR_BLUE
}

单点控制(single-pointcontrol)让程序真正软了起来, 将一个量保存在变量中. 程序中使用变量名替换这个量

第十三章 不常见的数据类型

p318

引用必须总是引用一个对象, 而指针则可以指向空值.
引用所指向的对象在改引用初始化后不能改变

全局变量应该加以说明

全局数据隐藏到类中, 使用static

不应该吧所有数据放在一个大对象中到处传递

不要实用全局变量存放中间结果

第四部分语句

第十四章 组织直线型代码

  • 设法组织代码, 使依赖关系变得非常明显
    data = ReadData();
    result = CalculateResultsFromData(data);
    PrintResult(result);
    这段代码看起来很舒服, 逻辑清理, 命名到位. 明显的表明了函数间的依赖关系
revenue.ComputeMonthly();
revenue.ComputeQuarterly();
revenue.ComputeAnnual();

这段代码, 前后依赖关系没有表现出来. 实际上计算季度收入需要先计算月收入 计算年收入需要季度收入

  • 使子程序名能凸显依赖关系
  • 使用子程序参数明确显示依赖关系

几个函数连续使用相同的参数, 说明之间极可能存在依赖关系.
几个函数使用不同的参数, 说明之间极可能不存在依赖关系

  • 对逻辑不清晰的代码 进行注释说明
  • 使用断言或者错误来处理错误的调用顺序

第十五章 使用条件语句

if 语句

  • 首先写正常的代码路径, 再处理不常见的情况. 使得正确情况的执行路径在代码中是清晰的.
  • 确保对于等量的分支是正确的(最好不要用>替换>= <替换<=) 防止off-by-one偏差一的错误. 这点emm
  • 把正常情况的处理放在if后面 不要放在else后面 (看了眼示例代码, 对于嵌套if非常重要)
  • 通用汽车公司做的分析发现 有五到八成的if语句都需要配有else语句
  • 确保考虑到所有的情况, 一串if elseif之后应该加上一个else检查其他情况, 防止有未考虑到的情况

case语句

  • default语句只用来检查真正的默认情况, 而不是用来处理你认为的最后一种情况. 否则
    你将失去case语句的标号(label)所提供的自动说明功能, 也丧失了default子句检错的能力
  • 利用default语句来检错
  • case语句后没有break应该注释说明

第十六章 控制循环

  • 不要滥用循环下标
    最好不要在循环体外 使用 依赖于循环下标最终取值的代码 可能会因为循环异常退出或者循环结束, 得到的下标并不是你想要的下标. 应该使用合适的变量用来标记在循环中是否遇到了你想要的情况
  • 考虑在while循环中使用break而不是布尔标记
  • 不要使用浮点数作为边界
  • 使用有意义的下标变量名, 防止下标串话.
  • 不要在循环中修改下标值

下面的代码就是下标串话, 本来第二个循环应该使用j. 这种bug可能不是很容易排查出来, i和j乍一看很像.

int  i, j;
for (i = 0; i < xxx; ++i)
{
xxxx
for (i = 0; j <xxx; ++j)
{

}
}

低效的程序员会随意做一些试验, 直到他们找到了一种看上去能工作的组合. 如果某个循环没有按照想象工作,低效的程序员可能会把<改为<=. 如果还不行可能把下标+1或者-1. 这样最终可能碰出正确组合, 也有可能把原来的错误改成了另一个更微妙的错误. 即使这样随意的开发过程能够产生正确的程序, 这些程序员也不明白为什么这个程序是正确的.

第十七章 不常见的控制结构

递归前两天正好用过, 如果用的恰当的话 感觉很不错

我也不想去用…… =, =


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。