C++ Primer 学习笔记十七 —— 用于大型程序的工具
2013-06-09 18:00
543 查看
记录笔记原则:
1.用简单易懂的语言叙述自己的理解,避免照搬原文
2.用实例说明,避免空洞
3.多做总结和横向对比,避免片面
异常处理
为什么要用异常处理?
异常是用来简化错误处理的.
一般来说比较大的程序,对待错误处理有两种模式:1. 返回错误码;2. 异常处理,
异常处理机制:函数调用不用再检查返回值,而且可以在很高层统一捕获异常,而不用每层都检查,尤其是在复杂调用层次关系的时候,这样省略了很多if else语句;
举例说明:
1.返回错误码
抛出异常的类型
异常可以是任意类型(标准的或自定义的),只要是可复制的;
runtime_error类型是标准库异常类,throw runtime_error("some msg")创建了runtime_error对象;
一般在catch处理异常的时候,抛出异常的块中的局部存储已经不存在了;
不要抛出指针;
异常对象
在throw的时候由编译器创建的特殊对象,并初始化为被抛出对象的副本;
throw runtime_error("abc");
异常对象 = runtime_error("abc")
栈展开
throw抛出异常后,沿着函数调用链向上,查找catch,找不到则函数退出,继续查找,最后找不到的话调用terminate函数非正常终止程序,这个过程叫做栈展开;
在栈展开的过程中,退出函数时,编译器会释放局部对象(如果是类对象则调用析构函数),但是动态资源不会释放;
不要在析构函数中抛出异常,因为在栈展开期间,析构函数又抛出异常会导致terminate;
捕获异常
基类的catch形参可以捕获派生类型的异常对象;
catch子句执行结束后,继续执行try catch块后面的语句;
捕获所有异常
参数传递过程
throw后面的表达式——> 异常对象——>catch形参
标准库异常类
标准库异常类都有一个what()成员函数,返回C字符串;
exception 最常见问题,用法:exception()
runtime_error 运行时错误,用法: runtime_error("some msg")
bad_alloc new时分配失败,用法: bad_alloc()
自定义异常类
一般从标准库异常类派生出一个自定义异常类;
auto_ptr
异常安全:如果发生异常,被分配的动态资源也能正确释放;
作用:为动态分配的对象提供异常安全;
注意:
不能指向静态对象;
不使用两个auto_ptr指向同一个对象;
不能指向数组;
不能将auto_ptr存储在容器;
命名空间
一个命名空间定义了一个作用域,每个作用域内名字必须唯一;
全局命名空间
全局命名空间是隐式声明的,存在于每个文件中;
未命名的命名空间
只在包含该命名空间的文件中可见,相当于static声明,局部于一个文件可见;
建议使用未命名的命名空间取代文件中的static声明;
两种using用法
using std:cout; 引入到当前作用域中;
using namespace std; 引入到包含的父作用域中;
多重继承与虚继承
多重继承比起单个继承有什么特别的?
构造基类的顺序:按照派生列表中的顺序依次构造;
假如两个基类都定义同名的成员,在派生类调用时会出现二义性,需指明哪个版本;
虚继承
虚基类的初始化由最底层派生类的构造函数初始化,此时中间层派生类将忽略虚基类的初始化;
异常处理
为什么要用异常处理?
异常是用来简化错误处理的.
1.用简单易懂的语言叙述自己的理解,避免照搬原文
2.用实例说明,避免空洞
3.多做总结和横向对比,避免片面
异常处理
为什么要用异常处理?
异常是用来简化错误处理的.
一般来说比较大的程序,对待错误处理有两种模式:1. 返回错误码;2. 异常处理,
异常处理机制:函数调用不用再检查返回值,而且可以在很高层统一捕获异常,而不用每层都检查,尤其是在复杂调用层次关系的时候,这样省略了很多if else语句;
举例说明:
1.返回错误码
int funcA() { if (正常) { return 0; } else { printf 错误日志; return -1; } } int funcB() { int result = funcA(); if (result == 0) { return 0; } else { printf 错误日志; return -1; } } int funcC() { int result = funcB(); if (result == 0) { return 0; } else { printf 错误日志; return -1; } }2.异常处理
void funcA() { if (错误) { throw runtime_error(错误信息); } // 正常逻辑 } void funcB() { funcA(); } void funcC() { try { funcB(); } catch (const runtime_error &e) { printf 错误日志; } }
抛出异常的类型
异常可以是任意类型(标准的或自定义的),只要是可复制的;
runtime_error类型是标准库异常类,throw runtime_error("some msg")创建了runtime_error对象;
一般在catch处理异常的时候,抛出异常的块中的局部存储已经不存在了;
不要抛出指针;
异常对象
在throw的时候由编译器创建的特殊对象,并初始化为被抛出对象的副本;
throw runtime_error("abc");
异常对象 = runtime_error("abc")
栈展开
throw抛出异常后,沿着函数调用链向上,查找catch,找不到则函数退出,继续查找,最后找不到的话调用terminate函数非正常终止程序,这个过程叫做栈展开;
在栈展开的过程中,退出函数时,编译器会释放局部对象(如果是类对象则调用析构函数),但是动态资源不会释放;
不要在析构函数中抛出异常,因为在栈展开期间,析构函数又抛出异常会导致terminate;
捕获异常
基类的catch形参可以捕获派生类型的异常对象;
catch子句执行结束后,继续执行try catch块后面的语句;
捕获所有异常
catch (...) { // code }
参数传递过程
throw后面的表达式——> 异常对象——>catch形参
标准库异常类
标准库异常类都有一个what()成员函数,返回C字符串;
exception 最常见问题,用法:exception()
runtime_error 运行时错误,用法: runtime_error("some msg")
bad_alloc new时分配失败,用法: bad_alloc()
自定义异常类
一般从标准库异常类派生出一个自定义异常类;
class MyException: public runtime_error { }
auto_ptr
异常安全:如果发生异常,被分配的动态资源也能正确释放;
作用:为动态分配的对象提供异常安全;
// delete不会被执行,内存泄露了 void f() { int *p = new int(42); throw exception(); delete p; } // 自动释放内存 void f() { auto_ptr<int> ap(new int(42)); throw exception(); }
注意:
不能指向静态对象;
不使用两个auto_ptr指向同一个对象;
不能指向数组;
不能将auto_ptr存储在容器;
命名空间
一个命名空间定义了一个作用域,每个作用域内名字必须唯一;
全局命名空间
全局命名空间是隐式声明的,存在于每个文件中;
::member_name
未命名的命名空间
只在包含该命名空间的文件中可见,相当于static声明,局部于一个文件可见;
建议使用未命名的命名空间取代文件中的static声明;
namespace { int i; }
两种using用法
using std:cout; 引入到当前作用域中;
using namespace std; 引入到包含的父作用域中;
namespace aaa { int a; } int a; void func() { using namespace aaa; a = 1; // 错误,二义性,a看起来导入到了全局作用域中 ::a = 1; // ok aaa::a = 1; // ok }建议:避免使用using namespace方法,名字全部导入,容易造成命名空间污染;
多重继承与虚继承
多重继承比起单个继承有什么特别的?
构造基类的顺序:按照派生列表中的顺序依次构造;
假如两个基类都定义同名的成员,在派生类调用时会出现二义性,需指明哪个版本;
虚继承
class A {}; class B1: virtual public A {}; class B2: virtual public A {}; class C: public B1, public B2 {};virtual 关键字陈述了再后代派生类中共享该基类的单个实例的愿望;
虚基类的初始化由最底层派生类的构造函数初始化,此时中间层派生类将忽略虚基类的初始化;
异常处理
为什么要用异常处理?
异常是用来简化错误处理的.
相关文章推荐
- C++ Primer 学习笔记_87_用于大型程序的工具 -错误处理
- C++ Primer 学习笔记_89_用于大型程序的工具 -错误处理[续2]
- C++ primer第二次阅读学习笔记(第17章:用于大型程序的工具:异常处理)
- C++ Primer 学习笔记_90_用于大型程序的工具 -错误处理[续3]
- C++ Primer 学习笔记_87_用于大型程序的工具 --异常处理
- C++ Primer 学习笔记_92_用于大型程序的工具 --命名空间[续1]
- C++ Primer 学习笔记_88_用于大型程序的工具 --异常处理[续1]
- C++ Primer 学习笔记_92_用于大型程序的工具 --命名空间[续1]
- C++ Primer 学习笔记_91_用于大型程序的工具 --命名空间
- C++ Primer 学习笔记_95_用于大型程序的工具 --多重继承与虚继承
- C++ primer第二次阅读学习笔记(第17章:用于大型程序的工具:多重继承与虚继承) .
- C++ Primer 学习笔记_96_用以大型程序的工具 -多重继承与虚继承[续1]
- C++ Primer 学习笔记_93_用以大型程序的工具 -命名空间[续2]
- C++ Primer 学习笔记_97_用来大型程序的工具 -多重继承与虚继承[续2]
- C++ Primer 学习笔记_88_用于大型程序的工具 -错误处理[续1]
- C++ Primer 学习笔记_91_用以大型程序的工具 -命名空间
- C++ primer第二次阅读学习笔记(第17章:用于大型程序的工具:命名空间)
- C++ Primer 学习笔记_92_用来大型程序的工具 -命名空间[续1]
- C++ Primer 学习笔记_94_用来大型程序的工具 -命名空间[续3]
- C++ Primer 学习笔记_95_用来大型程序的工具 -多重继承与虚继承