C++ Primer学习笔记-----第十八章:用于大型程序的工具

1.异常处理

try
{
	try
	{
	}
	catch(bad_alloc)	//捕获特定异常
	{
		/**处理异常**/			
		throw;			//或者抛出,让外层的异常捕获处理
	}
}
catch(...)	//捕获所有内存未处理的异常
{
	/**处理异常**/
}

1.3.函数try语句块与构造函数

构造函数在进入其函数体之前首先执行初始值列表。如果在函数体内部捕获异常,因为在初始值列表抛出异常时构造函数体内的try
语句块还未生效,所以构造函数体内的catch语句无法处理构造函数初始值列表抛出的异常。

函数try语句块使得一组catch语句既能处理构造函数体(或析构函数体),也能处理构造函数的初始化过程(或析构函数的析构过程)。
例如:
template<typename T>
Test<T>::Test(std::initializer_list<T> il) try:vec(il)	
{	/**空函数体**/  }
catch(const std::bad_alloc &e)
{	/**处理异常**/	}

还有一种情况值得注意,在初始化构造函数的参数时也可能发生异常,这样的异常不属于函数try语句块的一部分。函数try语句块
只能处理构造函数开始执行后发生的异常。和其他函数调用一样,如果在参数初始化的过程中发生了异常,则该异常属于调用表达式
的一部分,并将在调用者所在的上下文中处理。

1.4.noexcept异常说明

对于用户即编译器来说,预先指定某个函数不会抛出异常显然大有裨益。
首先,知道函数不会抛出异常有助于简化调用该函数的代码;
其次,如果编译器确认函数不会抛出异常,它就能执行某些特殊的优化操作。

void fun()const & noexcept override {}typedef或类型别名中则不能出现noexcept.
在成员函数中,noexcept说明符需要跟在const及引用限定符后,而在finaloverride或虚函数=0之前。
所以的声明和定义都要有noexcept,或者都没有。

noexcept可以用在两种情况下:
1.确认函数不会抛出异常。
2.根本不知道如何处理异常。
编译器并不会在编译时检查noexcept说明。

下面两个函数等价:都不会抛出异常
void fun() noexcept;	
void fun() throw();		//旧版本

异常说明的实参

noexcept说明符接受一个可选的实参,该实参必须能转换为bool类型。
void fun() noexcept(true);		//不抛出异常

noexcept运算符

noexcept运算符是一个一元运算符,返回值是一个bool类型的右值常量表达式,表示给定的表达式是否会抛出异常。
和sizeof类似,noexcept也不会求运算对象的值。
noexcept(e)
当e调用的所有函数都做了不抛出说明且e本身不含有throw语句时,上述表达式为true,否则返回falsevoid f() noexcept(noexcept(g()));	//外层的noexcept是异常说明符,内层的是操作符。
f和g的异常说明一致:要异常都异常,不异常都不异常。

异常说明与指针、虚函数和拷贝控制

尽管noexcept说明符不属于函数类型的一部分,但是函数的异常说明仍然会影响函数的使用。
函数指针及该指针所指的函数必须具有一致的异常说明。也就是说,如果我们为某个指针做了不抛出异常的说明,则该指针将只能
指向不抛出异常的函数。如果显示或隐式说明了指针可能抛出异常,则该指针可以指向任何函数。

如果一个虚函数承诺它不会抛出异常,则后续派生出来的虚函数也必须做出同样的承诺。
如果基类的虚函数允许抛出异常,则派生类的对应函数既可以抛出异常,也可以不抛出异常。

当编译器合成拷贝控制成员时,同时也生成一个异常说明。如果对所有成员和基类的所有操作都承诺不会抛出异常,则合成的成员
是noexcept的。如果合成成员调用的任意一个函数可能抛出异常,则合成的成员是noexcept(false).而且,如果我们定义了一个
析构函数但是没有为它提供异常说明,则编译器将合成一个。合成的异常说明将与假设由编译器为类合成析构函数时所得的异常
说明一致。

1.5.异常类层次
在这里插入图片描述
可以定义自己的异常类

class MyExcept:public std::runtime_error
{
public:
	explicit MyExcept(const std::string& s):std::runtime_error(s){}
}

class MyExcept2:public std::logic_error
{
public:
	explicit MyExcept(const std::string& s,const std::string& s2):std::runtime_error(s),str(s2){}
	const std::string str;
}

2.命名空间

#include <string>
namespace ns
{
	namespace ns2{}
	inline namespace ns1{}	//内联命名空间,外层作用域可直接访问内部的成员	
	namespace{}				//未命名命名空间,可直接访问成员,每个文件的未命名命名空间不同
}

namespace myns = ns::ns2;	//简化命名空间命名

using声明:扼要概述

一条using声明语句一次只引入命名空间的一个成员。
using ns::meb;

using指示:把命名空间中的成员注入外层作用域中

using namesapce ns;	//ns命名空间所有的名字都可见,这样就无须添加任何前缀限定符了

3.多重继承与虚继承

class Base{}
class Derived1:public virtual Base{}		//虚继承
class Derived2:public virtual Base{}		//虚继承
class SubDerived:public Derived1,public Derived2	//SubDerived中只有一份Base成员
{
public:
	SubDerived():Base(),Derived1(),Derived2(){}	//直接调用虚基类的构造函数,进行初始化
}	

初始化:先初始化虚基类的成员(调用虚基类的构造函数),在顺序初始化其他直接基类。
析构:最后执行虚基类的析构函数。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值