C++ 学习笔记 之 《Thinking in c++》 第二卷

本文探讨了C++中的异常处理策略,包括异常规格说明、异常中立库的概念及最佳实践。此外,还详细介绍了C++标准库中的字符串类String的使用方法,包括初始化、操作和管理字符串的方法。

第一章 异常处理

 

1、  使用断言(assertion)来表示和强悍程序中的不变量(invariant),是经验丰富的软件工程师的确切标志。

2、  增强错误恢复能力是提高代码健壮性的最有力的途径之一。

3、  在异常匹配过程中,为了避免对象被切割和再次拷贝异常对象,最后是通过引用而不是通过值来捕获对象。

4、  在异常匹配过程中,不会将一种异常类型自动转换为另一种异常类型。

5、  在异常匹配过程中,比较有意义的做法是,首先捕获派生类异常,并且将基类放到最后用于捕获其他不太具体的异常。

6、  用省略号作为异常处理器的参数列表可以创建捕获所有异常的异常处理器。它是一个全能捕获者,这种catch子句经常用于清理资源并重新抛出所捕获的异常。

7、  如果一个异常没有被任何一个层次的异常处理器捕获,terminate()函数(from <exception>)将被调用。默认情况下,abort函数被调用,是程序执行异常终止而退出。

8、  abort()被调用时,程序不会调用正常的终止函数,全局对象和局部静态对象的析构函数不会被执行。

9、  局部对象的析构函数抛出异常时,栈正在进行清理工作或者是全局或静态对象的构造函数或者析构函数抛出一个异常,也会导致terminate()函数被调用。

10、              通过set_ternimate()函数,可以设置自己的terminate()函数。

11、              抛出异常或者由于某种原因导致一个异常被抛出的析构函数通常被认为象征这拙劣的设计或糟糕的代码。

12、              如果在构造函数中抛出异常,析构函数并不会被调用,因为对象尚未建立完毕。为了防止资源泄露,读者必须使用下列两种方式之一来防止“不成熟的”资源分配方式:a,在构造函数中捕获异常,用于释放资源;b,在对象的构造函数中分配资源,在析构函数中释放资源。

13、              Auto_ptr类模板是在头文件<memory>中定义的,它的构造函数接受一个指向类属类型的指针作为参数。它重载了指针运算符*->,以便对持有的auto_ptr对象的原始指针进行前面接啊好哦的那些运算。

14、              一般来说,使用标准异常类比用户自己定义异常类要方便快捷的多。如果不满足要求,也可以从标准异常类派生出自己的类。

15、              Logic_error介绍,用于描述程序中出现的逻辑错误,例如传递无效的参数。From< stdexcept>

16、              Runtime_error介绍,运行时错误是指那些无法预料的事件造成的错误,例如硬件故障或内存耗尽。

17、              用户最好总runtime_error或者logic_error派生出自己的饿类,二不要直接从std::exception类派生。

18、       本条目是介绍标准错误类的,这个blog里的插入图片功能太垃圾,用不了。       

19、              ios::failure也是从exception派生的,但是它没有子类。

20、              可以直接使用下面两个表中所列的异常类,或者把它们作为基类来派生自己的更加具体的异常类。

21、            本条目是介绍标准错误类的,这个blog里的插入图片功能太垃圾,用不了。 

22、            本条目是介绍标准错误类的,这个blog里的插入图片功能太垃圾,用不了。

23、              异常规格说明:从好的编码策略、好的文档和便于函数调用这几个方面来说,当读者编写可能抛出异常的函数时,最好考虑使用异常规格说明。

24、              void f() throw(toobig,toosmall,divzero);括号中列出函数可能抛出的异常

25、              void f() ;传统的函数声明,意味着函数可能抛出任何异常。

26、              void f() throw(); 意味着函数不抛出任何异常。

27、              如果函数抛出了意外的异常,则unexpected()函数被调用,它默认调用terminate()函数,可以通过set_unexpected()设置自己的unexpected()函数。

28、              由于异常规格说明在逻辑上也是函数声明的一部分,所以在继承层次结构中也必须保持一致。在派生类中,可以使用派生异常类的返回值来代替异常规格说明中的异常基类对象的引用。这种行为被称为协变。

29、              相应的:参数类型不能协变---在覆盖虚函数的时候不允许修改函数的签名。

30、              当无法知道会触发什么异常时,不要使用异常规格说明。这就是为什么模板类,也就是标准C++库的主要组成部分不使用异常规格说明的原因。异常规格说明主要是万恶非模板类准备。

31、              遵守内聚设计原则每个函数只做一件事情。异常安全的代码能够是对象保持状态的一致性而且能够避免资源泄露。

32、              重要的是,知道所有的新增部件都被安全地分配到内存并初始化之前,不要修改原对象的状态。

33、              不会默默的吞没异常的软件库被称作异常中立的。对于读者来说,始终需要努力写出类型安全并且异常中立的软件库。

34、              下面几个条目中列出的几个情况下不应该使用异常。

35、              不要在异步事件中使用异常。异常依赖于程序运行栈上的动态函数调用链,然而异步事件必须有完全独立的代码来处理,这些代码不是正常程序流程的一部分。不要在中断处理程序中抛出异常。

36、              不要在处理简单错误时使用异常。如果能得到足够的信息来处理错误,那么就不要使用异常。这样,C++的异常机制可以相当有效,它们被隔离起来只用于处理程序级的异常情况。

37、              不要将异常用于程序的流程控制,部分原因是异常处理系统的效率比普通的流程控制差很多,同样,会令类或函数的使用者混乱。

38、              不要强迫自己使用异常。

39、              新异常,老代码。当正在编写一个供其他人使用的库时,特别是当无法知道他们如何响应致命错误时,慎重的考虑异常非常重要。如同,标准库中没有使用异常。

40、              任何时候如果要使用异常规格说明,或调用异常规格说明的函数,最好编写自己的unexpected函数,在这个函数中将消息记入日志,然后抛出异常或者终止程序。

41、              应该比=避免在模板类中使用异常规格说明,因为无法预料模板参数类所抛出的异常的类型。

42、              不理会构造函数中出现的故障二继续运行,肯定会导致灾难性的后果,所以构造函数是抛出异常最重要的位置之一。当构造函数抛出异常时,用户必须主要对象没补的指针和他的清理方式。、

43、              不要在析构函数内部触发异常。如果析构函数中调用的函数可能会抛出异常,应在这个析构函数中编写一个try块,并把这些函数放在try块中,析构函数自己处理所有这些异常,绝对不能有任何一个异常从析构函数中抛出。

44、              避免悬挂指针,请使用auto_ptr或其他智能指针类型来处理指向堆内存的指针。

45、              异常机制的重要设计目标之一是,当异常没有发生时,它不应该影响系统的运行速度。


第二章 防御性编程

 

1、  典型软件产品的复杂性保证了测试人员总有做不完的工作,但是我们努力不断。

2、  本章中读者将学到一些经验,不管项目是什么规模,这些经验都能够帮助程序员创建出健壮的代码。

3、  代码的其中一个内涵是对问题解决方法的描述。在设计循环的时候,程序员应该能够清楚地告诉读者其准确的想法是什么。在程序中的某个特定的地方,应该能够大胆的声明某些条件或其他一些控制方法。这种声明叫做不变量(invariant)。因为在代码中它们出现的那一点是它们应该恒为真。

4、  不变量通常仅仅依赖于编写的代码,所以这些不变量条件始终持有程序设计是否已经正确的实现的证据。在这种情况下,可以明确的使用断言。

5、  断言的意图是验证设计决定的,造成它失败的唯一原因应该是程序逻辑有缺陷。理想的结果是在开发阶段就解决掉所有违背断言的情况。如果某个条件不完全在程序的控制之下,那么不要对这个条件使用断言。特别是不应该使用断言来验证函数的参数;参数错误的饿情况下,应该抛出logic_error异常。

6、  如果得不到一个可供参考的系统,然后在它的基础上提出改进意见,人们无法明晰的说明软件需求。

7、  以迭代方式开发程序的能力是面向对象方法的最大优势之一,但是这需要有才干的程序员,这些程序员应该能够精心制作扩展力非常强的代码。修改现有程序是困难的。

8、  极限编程仅仅是众多支持快速开发实践方法的一种。

9、  在这一节里,要探究一种便于使用的自动单元测试工具框架,它能够是我们成功开发出灵活性的可扩展程序。

10、              通过编写单元测试程序,开发者能够对下面的两点关键内容获得足够的信心。

11、              1)我理解需求

12、              2)我的代码符合需求。

13、              先编写单元测试程序是一种能够确保将要编写的代码能够正确工作的最好方法。

14、              测试程序+编码 比直接编码更快!!

15、              先编写测试程序同样能够防止边界条件破坏程序,使代码更加健壮。

16、              有太多的开发人员常常只希望他们的代码在获得符合要求的输入时能够产生预期的输出,他们只用眼镜检查程序的输出。

17、              只要能用,做最简单的!!

18、              最好的调试习惯是使用本章开始的时候所述的断言;使用断言可以在程序代码真正出现问题之前,帮助程序设计人员找到其他的逻辑错误。

19、              用于跟踪代码的宏:

20、              1#define TRACE( ARG) cout<<#ARG<< endl; ARG 处理跟踪语句代码。

21、              2#define  D(a) cout<<#a”=[”<<a<<”]”<<endl; 检查中间结果的值。

22、              本书中介绍了几个测试类,我感觉没有必要详细了解。倒是有必要好好学习一下CppUnit的使用。

23、              下面是介绍CppUnit的很好的在线文档:

24、              http://morningspace.51.net/resource/cppunit/cppunit_anno.html

25、              http://blog.youkuaiyun.com/cpluser/archive/2004/09/21/111522.aspx

26、              http://blog.youkuaiyun.com/cpluser/archive/2004/09/21/111522.aspx

27、              http://blog.youkuaiyun.com/lengxingfei/archive/2006/04/17/666428.aspx

28、              http://www.vckbase.com/document/viewdoc/?id=1762


第三章 深入了解字符串

第三章 深入了解字符串

1.         C++ String与它们在C中的前身最主要的不同是,隐藏了它所包含的字符序列的物理表示。从而极大的减少了C3钟最常见并且最具破坏性的错误:超越数组边界、通过未初始化或者被赋以错误值的指针来访问数组元素,以及在释放了某一数组原先分配的存储单元后仍保留悬挂指针。

2.         C++没有定义字符串类内存布局的确切实现。

3.         创建String对象举例:

4.         string inBlandk;//声明一个空串,被初始化为没有字符。

5.         string heyMom(“Where are my socks?”);//使用常量字符串初始化。

6.         string standardReply=”Beameded into deep”;//使用等号初始化

7.         string useThisOneAgain(standardReply);//使用一个string对象初始化另一个string对象。

8.         还可以如下初始化一个string 对象:

9.         使用c语言的char数组或者string对象的一部分。String  s2(string_obj,0,8);

10.     operator +把不同的初始化数据源结合在一起。

11.     string对象的成员函数substr()创建一个字串。

12.     substr()将开始位置作为第一参数,将待选的字符个数作为第二个参数。两个参数都有默认值,如果使用空的参数列表来调用substr(),将会构造出string对象的整个副本,所以,这是复制string对象的一个简便方法。

13.     assert();from <caccert>

14.     不可以使用单个的字符、ASC 2 或者其他整数值初始化字符串。但是可以用单个字符的多个拷贝来初始化字符串。

15.     string okay(5,’a’);//第一个参数指定字符个数,第二个参数指定要拷贝的字符!

16.     string无需程序员干预,它们可根据需要自行扩充规模。这个特性在程序员不知道字符串要改变的幅度时会更加有用。

17.     当字符串增长时,成员函数append()insert(),很明显的重新分配了存储空间。

18.     string类提供了几个工具以便可以监视和管理它们的规模,如下:

19.     size()函数返回当前存储的字符个数,作用等同length()

20.     capacity()函数返回当前分配的存储空间爱你的规模。

21.     reserve()函数提供了一种优化机制,它按照程序员的意图预留一定的空间以备将来使用。

22.     resize(),当要生成的新串的规模大于当前的规模时或者需要截断原字符串时,这个函数会被调用。默认是在末尾追加空格。

23.     insert()函数向字符串中插入字符,原来的字符会自动改变位置,空间自动增大。

24.     如果希望字符串的大小保持不变,就应该使用replace()函数。它有很多重载版本。

25.     数据成员nposstring类的一个静态常量成员,它表示一个不存在的位置。

26.     当有新字符复制到现存的一串序列的中间时,replace(0并不增加string的存储空间规模,这点与insert()不同。但是replace()也会在必要时增加空间。

 

2008-7-31今天事情有点多,没有完成预定计划。每天将首先保证第3、4章的学习任务。然后才研究公司的代码。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值