《代码大全2》学习笔记3

第三、四部分——变量、语句

“在声明变量时初始化”——减少未赋值的风险。

“尽可能减少变量的存活时间”——感觉如果按照推荐,一般子程序都写的很短,那么这个也就不重要了吧。

“一个好记的名字反应的通常是问题,而不是解决方案,是what而不是how”

“避免使用相似含义的名字,如果你能让2个变量交换名字还不妨碍理解的话,就说明都要重新改名了。”——越功能简单越名字容易相似,哪那么好改啊。

“避免使用数字,什么file1,file2”——有时候就是图省事,哈

“阅读代码的次数远远多于编码,所以命名变量应该是阅读方便而不是编写方便”——不过现在公司都是一人维护一个模块,基本很少有别人来读代码。

“编码使用神秘数值,要么枚举要么常量”

“有除法预防除0错误”——经常犯

“检查中间结果溢出”——这个很重要,考虑最后结果是不是会溢出,有时候中间变量的溢出更会导致问题。

“避免数量级相差巨大的数之间的加减”——浮点型很难保证精度。

枚举的好处:

1、可读性好。

2、返回值用枚举替代bool,可以返回更多的结果,比如有2种失败等。

——2种模式下用一个方法返回是哪种模式,千万别有bool而要用枚举,否则新增需求是非常麻烦的。

3、枚举对第一项和最后一项再给一个特殊的名字,便于循环

enum{

color_first=0,color_red=color_first,color_green,color_blue,……color_black,color_end=color_black,

};

——循环时的确方便

使用typedef来自定义数据类型,方便修改,同时方便移植。

——方便移植倒是很理解,不过方便修改这点倒是很少遇到。

把相关元素组织到结构体里面,然后对结构体操作。好处在于交换2组数据时非常方便。

用结构体传递参数给方法。好处是再增加一个参数时,不用那么麻烦的再改好几个地方了,而且函数声明定义也不会那么长一串。

把指针操作限制在子程序里面或者类里面操作。——比如链表里面的指针操作。

delete指针时销毁内存——这点挺好的,delete前bzero一把,就不会导致使用已经delete的数据,有时候崩溃有时候没问题的情况了。但是有个问题,如果是标准数据类型还好,或者结构体也还好,有长度,对于有string的类,怎么bzero啊,根本就没有具体长度。???

方法传递变量,建议用const引用来传递,减少一次复制。

把if-else里面正常处理和处理常见情况放在最前面处理。

default只用来处理输入错误。

注意空循环里有没有sleep,可能导致cpu占满。

循环条件要尽可能短,嵌套循环不要超过3层。把长寻访放到子程序里面。

goto在分配资源,使用资源后再释放资源的子程序里面比较有用,尤其是出错要退出的时候,大量的释放资源的代码很重复。

——用宏定义把所有的释放都变成一条语句也可以,不过似乎很难看的样子。

第十八章《表驱动法》

凡是能用逻辑语句来选择的事物,都可以通过查表法来选择。

使用逻辑虽然直白,但是逻辑太多,查表法反而更好。

——比如以前设计一个程序,查找某ip段属于某个域,用x[256][256]-list,查找速度和理解性上都比用数字段好多了。

把结果提前计算出来,放在表中直接查阅,比现计算要快。

或者把计算出来的结果存在表中,避免下次计算。

“最好是找一种好的方案同时避免引发灾难,而不要试图去寻找最佳答案。”

第五部分:代码改善

20软件质量概述:

外在特征:(给用户用)

正确性(错误的稀少)、可用性(用户学习和使用一个系统的容易程度)

效率(占用系统资源多少,执行速度)、可靠性(很长的雾故障时间)

完整性integrity【应该叫完善性】(如拒绝访问未授权数据、确保日期字段是有效数据等)

适应性(如果即可以在xp小跑,也能在w7下跑)、精确性(在正确性的基础之上判定完成工作的优劣程度)

健壮性(接受无效输入的容错处理,和压力承受能力。)

内在特征:(给其他程序员用)

可维护性(是否容易修改、容易增加功能、提供性能、修正缺陷)

灵活性(用于其他用途时,修改的难度)【感觉没啥意义,其他用途还不如重写呢。写代码的时候就考虑灵活性,会导致限制很大】

可移植性(编译移植到其他平台)【与其为了可移植性导致效率下降,真不如重写一个算了。比如libevent为了夸平台,win上用的竟然是select。ACE在win上的完成端口还可以,但是在linux的epoll不是很好】

可重用性(某些功能用到其他程度里面的难易程度)

可读性(代码好读否)、可测试性

可理解性(可读性的加强版,更容易了解整体设计)

检查通读代码容易发现接口错误。

功能测试容易发现控制缺陷。

非正式测试一遍只能有50-60%的测试覆盖率。

编写无缺陷程序可能会让我们花费更少的时间。

21 协同构建:

相互协作的好处:开发人员都有盲点,但是其他人不一定有相同的盲点,所以让其他人检查自己的代码是有好处的。

结对编程:一个敲代码,一个在一边看。好处是人在有压力之下效率更高缩短时间表,能改善代码的质量和可读性,传播公司文化,执导培养新人等。【感觉好可怕,被一个人盯着去编码,难受】

正式检查、评审:

参加人员:

主持人(负责分配人员,分配任务,检查汇报结果,跟踪指派的结果。不能是作者)

作者(直接写文档、代码的人)

评审专家(在开会前找出缺陷,提交给作者和主持人)

记录员(评审专家一员,记录问题的确认,和新问题的记录)

步骤:

计划(作者提交主持人,主持人选定专家,开会时间)

概述(可选,加入专家不熟悉具体情况,作者做介绍)

准备(每个专家独立检查,有问题提交主持人和作者)

开会(主题是确认是不是问题,到确认就可以了,不应该去讨论解决方案。有新问题记录。不应该超过2个小时,很难保持精力,同时时间太长,专家在之前就不会认真找问题而在希望在会议中去找了。)

返工(确认记录,修复之)

跟进(主持人督查返工情况)

第三小时会议(有关人员讨论解决方案)

注意事项:

“很多公司发现,去掉或者合并某些步骤往往增加而不是降低了成本”

对事不对人,目的是找出缺陷,而不是探索替代方案,也不是批评作者水平低。

“90%的错误是在准备时发现的,10%是在会议上发现的。”

22开发者测试:

单元测试(单个子程序,单个类,或者单个小程序)

组件测试(个人理解是某个独立模块或子系统,涉及到多个程序员)

集成测试(多个子系统,多个开发团队)

回归测试(修改bug后的再次测试,防止这次修改导致其他错误)

系统测试(某些性能,安全,资源消耗等问题只能在这个层面测试)

测试是为了找出问题,测试永远不能证明程序中没有错误,测试本身并不能改善代码质量。

【建议先写测试用例再编码——本书提到很多次了,估计作者应该有切身体会。】

先写测试用例,会让你在开始写代码之前思考一下需求和设计,而这会催生出更高质量的代码。

使用容易手工检查的值作为测试输入。

“绝大多数错误都是在少数类中。”

“19%的错误都是对设计或需求的错误理解或误解导致的。”

测试数据本身出错的密度比测试代码还要高,可能导致程序员消耗几个小时的时间,发现原来是数据错了。

保留测试记录【公司一般都有bug记录和关系,感觉可以增加的就是“查找错误消耗的时间,修正错消耗的时间”】

23调试:

调试不是改进代码的方法,而是诊断代码缺陷的方法。

科学调试方法:

1、把错误状态稳定下来(找出必先的大致条件)

2、确定错误来源(收集错误相关数据,分析,构造一个假说,正式或者证伪这个假说)

3、修补缺陷

4、测试

5、查找还有类似错误否

如果没有重复性,就要考虑是不是初始化文件,或者是与时间有关,或者是野指针。

蛮力调试:对代码全部检查,从头开始设计和编码等等。

“对蛮力测试,你反应是做不了。但是往往花了2个小时去调试本来30分钟就能写完的代码。”

“动手之前要先了解问题。匆忙动手解决问题是你所能做的最低效的事情之一。”

“理解程序本身,而不仅仅是问题。”

“保存最初的源代码”【比如上传cvs,这点很重要,深有体会】

“修改代码一定要有适当的理由,而不是改动这里试试能不能解决问题。”

“一次只做一个改动。,改动越多越容易出错。”

“修改后检查自己的改动。”【修改后对比原先的代码很重要】

“把编译器设定为最严格,修改所有的报警的地方”【有必要吗,比如vc里面给一个枚举赋整型值也告警,这也都得修改吗?】

24重构

重构的理由:

具体见P565

比如:

代码重复(同样的一段代码,到处都是,每次一个修改得改好几个地方)

太多参数的子程序

……

超前设计(将来才会用到的功能)【感觉和前面的可维护性矛盾啊,不考虑超前,怎么适应未来的扩展功能?】

重构不等于重写。

----------------------------

【留个问题,上班的时候问问,g++在调试的时候能改内存的值吗?】

答:可以  gdb里面,输入“p   变量=新值”就可以了,另外类的符号重载在这里是无效的,比如string abc;那么不能p abc=“123” 而yoga用p abc.assign("123")

另外顺便发现了string的几个特点

char ch1[20] = {0};
 ch1[0] = ‘a‘;
 ch1[10] = ‘b‘;
 string abc(ch1,20);
 cout <<abc.length()<<";"<<abc.size()<<";"<<abc<<";"<<abc.c_str()<<";"<<endl;

打印结果应该是:20;20;ab;a;

时间: 2025-01-08 22:58:54

《代码大全2》学习笔记3的相关文章

C PRIMER PLUS 学习笔记(一)

1显示程序执行的窗口一闪即逝.可以添加如下语句: getchar() 作用是获取键盘输入. 2 inf 和 nan float toobig = 3.4e38 * 100.0f; float not_a_number = asin(1.2);//math.h printf("%e \t %e\n", toobig,not_a_number); inf-表示无穷大,nan-Not-a-number 3 long double 的输出格式 long double x; x = 3.2e-5

C++ Primer Plus学习笔记之虚函数

C++ Primer Plus学习笔记之虚函数 C++语言的多态性有两种类型:静态多态性和动态多态性.函数重载和运算符重载就是静态多态性的具体表现,而动态多态性是指程序运行过程中才动态的确定操作所针对的对象,它是通过虚函数实现的: 1,虚函数的概念: 一个指向基类的指针可用来指向从基类派生的任何对象,这样就可以达到一个接口多个实现的访问了:虚函数是在基类中被冠以virtual的成员函数,它提供了一种接口界面.虚函数可以在一个或者多个派生类中被重新定义,但要求在派生类中从新定义时,虚函数的函数原型

C++ Primer Plus学习笔记之静态成员

C++ Primer Plus学习笔记之静态成员 关键字static可以用来说明一个类的成员(包括数据成员和成员函数),这样的成员被称为静态成员: 1,静态数据成员 在一个类中,若将一个数据说明前加上static,则该数据成为静态数据,静态数据成员被该类的所有对象共享.无论建立多少个该类的对象,都只有一个静态数据存储空间: 具体语法如下: 类型名 类名::静态数据成员[=常量表达式] 其中,常量表达式用于初始化类的静态数据成员: 静态数据成员属于类,而不属于对象,因为静态成员的存在是不依赖于某个

C++ Primer Plus学习笔记之继承类的初始化顺序

C++ Primer Plus学习笔记之继承类的初始化顺序 基类的构造函数,析构函数和操作符函数operator=是不能被派生类继承的: 那么,当创建一个派生类对象时,怎样调用基类的构造函数对基类的数据进行初始化呢??? 答案是:构造函数执行时遵行先兄长(基类),再客人(对象成员),后自己(派生类)的顺序: 另一方面,执行析构函数时,先执行派生类的析构函数,再执行基类的析构函数.原因是,对基类的破坏隐含了对派生类的破坏,所以派生类的析构函数必须先执行: #include<iostream> u

C++ Primer Plus学习笔记之运算符重载

C++ Primer Plus学习笔记之运算符重载 1,成员函数和友元函数选择的建议 下面我们先看两个例子: 成员函数重载 #include<iostream> using namespace std; class Complex { public: Complex(double r=0,double i=0) { re=r; im=i; } Complex operator+(const Complex& obj); Complex operator!(); void Display

C++ Primer Plus学习笔记之拷贝构造函数

C++ Primer Plus学习笔记之拷贝构造函数 1,什么是拷贝构造函数 拷贝构造函数有两个含义: 首先,它是一个构造函数,当创建一个新对象时,系统自动调用它: 其次,它将一个已经定义过的对象的数据成员逐一对应的复制给新对象: 如果一个类没有显式定义拷贝构造函数,C++编译器可以为该类产生一个缺省的拷贝构造函数.这个缺省的拷贝构造函数采用C的方式,将拷贝对象的内存一个字节一个字节的拷贝到拷贝对象的内存中(内存拷贝): 2,拷贝构造函数的作用 (1)创建一个新对象,并将一个已存在的对象拷贝到这

c++ primer plus学习笔记(栈指针)

c++ primer plus 程序清单14.5 程序清单14.6 模拟如下情况: 某人将一车文件交给plodson,如果plodson的收取蓝是空的,他将取出车中最上面的文件,将它放入收 取蓝,如果收取蓝是满的,他将取出栏中最上面的文件,并进行处理,然后放入发出蓝,如果收取蓝不空不满 plodson将采用抛硬币的方式来决定采取措施. 很明显,我们需要使用栈去管理上述文件. 1 #ifndef STACK_H_ 2 #define STACK_H_ 3 4 //定义类模板 5 template

《c++primer》学习笔记

花了一个多月时间总算是把这本书看完了,再去看自己家游戏的服务器的代码还是很难懂,里面用到了好多boost库的东西,不过这些东西很多都已经加入了c++11的新标准里了,要到自己能做服务器还得接着学,所以接下来的一个月开始看<C++标准库>. 把看<c++primer>的时候抄的笔记先誊在这里方便以后参考. #include 来自标准库的头文件使用<> 来自非标准库的头文件使用"" ------------------------------------

c++ primer plus 学习笔记

我的机子用Xcode,单位是字节 0开头为8进制 0x为16进制 cout默认输出的是10进制 wchar_t 宽字节,它是一种足够大的整形类型,可以用来表示的是比如中文的编码 c常量一旦被定义,就不能被修改(const) 浮点数,c++中浮点数在计算内存中由两部分组成,一部分为基数,一部分用来表示浮点,这个浮点是用二进制来表示. 非常大或者非常小的数可以用e表示法来表示 这个程序充分说明了精度的问题,double能保存更高的精度.对于c++来说float只能保存6位有效数字,如果需要更高的精度

《C++ Primer》学习笔记【第一部分 基本语言】

第2章 整型的赋值:当我们试着把一个超出其范围的值赋给一个指定类型的对象时,结果如何?答案取决于类型是signed还是unsigned的.对于unsigned,编译器会将该值对unsigned类型的可能取值数目求模然后取所得值:对于signed类型,未定义行为,很多处理器处理方式和unsigned类似. 字符串字面值的连接:std::cout << "multi-line" L"literal " << std::endl;结果未定义,即连接