《STL标准程序库》笔记1

来源:互联网 发布:中国报告大厅数据库 编辑:程序博客网 时间:2024/05/02 01:33

5.7

C++异常处理

class Error

void f()

{

try

{

...throw Error();

}catch( const Error e )

{

......

}

void f() throw(bad_alloc); //f只能抛出bad_alloc异常

void f() throw(); //f不抛出任何异常

关键字explicit

class Stack {

explicit Stack( int  size ); //create stack with initial size

...

}

在这里,explicit非常重要,如果没有explicit,那么这个这个类将有能力将int自动转换为Stack。一旦这种情况发生,你甚至可以给Stack指派一个整数值而不会引起任何问题:

Stack s;

...

s = 40; //将会创建一个新的40个空间的Stacks

自动类型转换动作会把40转换为有40个元素的Stack,并指派给s,这几乎肯定不是我们所要的结果。如果我们加上explicit,上述赋值动作就会导致编译错误。

新的类型转换操作

1.static_cast

将一个值以合逻辑的方式转换。这可看作是【利用原值重建一个临时物件,并在设立初值时使用类型转换】。唯有当上述的类型黄钻更换有所定义,整个转换才会成功。所谓有所定义,可以是语言内建规则,也可以是自定义的装换动作。例如:

float x;

...

cout<< static_cast<int>(x); //print x as int 

....

f( static_cast<string>("Hello")); //call f() for string instead of char*

2.dynamic_cast

将类型向下转换为其实际类型。这是唯一在执行期进行检验的转换动作。你可以用它来检验某个类型,例如:

class Car;

class Cabriolet : public Car {

...

};

class Limousine : public Car {

...

};

void f(Car *cp)

{

Cabriolet *p = dynamic_cast<Cabriolet*>(cp);

if( p==NULL ) {

//did nor refer  to an object of type Cabriolet

...

}

}

dynamic_cast失败时抛出一个bad_case异常。一般应尽量避免这种写法。

3.const_case

设定或去除类型的常数性(constness),亦可去除volatile修饰,除此之外不允许任何转换。

4.reinterpret_cast

。。。使用此转换带来不可移植性。

注意:这些操作符都只接受一个参数。看一下例子:

static_cast<Fraction>(15,100)

在这个例子中你得不到你想要的结果。它只用一个数值100,将15100转换为分数的正确做法是Fraction(15,100);

常数静态成员(Constent Static Menbers)的初始化

我们能够在class中对定义常数静态成员直接赋予初值。初始化后,这个常数便可用于class中,例如:

class MyClass {

static const int num = 100;

int elems[num];

....

};

注意:你还必须为class之中定义的常数静态成员,定义一个空间:

const int MyClass::num;

main()的定义

正确而可移植的main()的唯一写法。根据C++标准规格,只有两种main()是可移植的:

int main()

{}

int main( int argc, char* argv[] )

{}

这个argv(命令参数列)也可定义为char**

返回类型必须为int。你可以使用return语句来结束main(),但不必一定如此。这一点和C不同,换句话说,C++main()的尾端定义了一个隐含的:

return 0;

这意味着如果你不采用return离开main(),实际上就表示成功退出(传回任何一个非零值都代表某种失败)。

标准异常类别

语言本身的异常

此类异常用以支撑某些语言特性,所以,从某种角度来说它们不是标准程序库的一部分,而是核心语言的一部分。如果一下操作失败,就会抛出这一类异常。

全局运算符new操作失败,会抛出bad_alloc异常(nothrow版本除外)。由于这个异常可能於任何时间在任何较复杂的程序中发生,所以可以说是最重要的一个异常。

执行期间,当一个动态类型转换动作失败时,dynamic_cast会抛出bad_cast异常。

执行期类型辨别过程中,如果交给typeid的参数为0或空指针,typeid操作符会抛出bad_typeid异常。

如果发生非预期的异常,bad_exception异常会接手处理,方式如下:当函数抛出异常规格以外的异常,bad_exception就会唤起unexpected()。例如:

class E1;

class E2; //not derived from E1

void f() throw(E1) //throws only exceptions of type E1

{

throw E1(); //throws exception of type E1

throw E2(); //calls unexpected()which calls terminate()

}

f()内抛出类型E2的异常,这种动作违反了异常规格(exception specification)的设定,于是唤起unexpected(),后者通常会唤起terminate()中止程序。

然而如果你在你的异常规格列出bad_exception,那么unexpected()总是会重新抛出(rethrowsbad_exception异常。

class E1;

class E2; // not derived from E1

void f() throw( E1, std::bad_exception )

{

throw E1(); // throws exception of type E1

throw E2(); // calls unexpected(), which throws bad_exception

}

因此,如果异常规格罗列了bad_exception,那么任何未列于规格的异常,都将在函数unexpected()中被bad_exception取代。

(你可以修改unexpected()的具体操作。然而只要定义有异常规格,函数就绝不会抛出规格以外的异常)

C++标准程序库异常总是衍生自logic_error。理论而言,我们能够透过一些手段,在程序中避免逻辑错误——例如对函数参数进行额外测试等等。所谓逻辑错误包括未被逻辑前提或违反class的不变性。C++标准程序库提供一下逻辑错误类型:

invalid_argument表示无效参数,例如将bitsetarray of  bits)以char而非'0''1'进行初始化。

length_error指出某个行为可能超越了最大极限,例如对某个字符串附加太多字符。

out_of_range指出参数值不在预期范围内,例如在array的群集(collection)或字符串(string)中采用一个错误索引。

domain_error指出专业领域范畴内的错误。

此外,标准程序库的I/O部分提供了一个名为ios_base::failure的特殊异常。当资源串流(data stream)由于错误或由于到达尾端而发生状态改变时,就可能抛出这个异常。

程序作用域(scope of a program)之外发生的异常

衍生自runtime_error的异常,用来指出不在程序范围内,且不容易回避的事件。C++标准程序库指针对执行期错误提供了一下三个classes

range_error指出内部计算时发生区间错误(range error)。

overflow_error指出算术运算发生上溢位(overflow)。

underflow_error指出算术运算发生下溢位(underflow)。

标准程序库所抛出的异常

C++标准程序库自身可能抛出range_errorout_of_rangeinvalid_argument异常。也可能间接抛出任何异常。尤其是bad_alloc异常。

异常类型的头文件

exceptionbad_exception定义于<exception>

bad_alloc定义于<new>

bad_castbad_typeid定义于<typeinfo>

ios_base::failure定义于<ios>

其他异常类型都定义于<stdexcept>

异常类型(Exception Classes)的成员

为了在catch子句中处理异常,你必须采用异常所提供的介面。所有标准异常的介面只含一个成员函数:what(),用以获取附加信息。它传回一个以null结束的字符串:

namespace std {

class exception {

public:

virtual const char* what() const throw();

...

}

}

被传回的字符串,期内容由实现者定义,它很大程度决定了帮助级别和信息的详细度。注意:该字符串可能以null结尾的“multibyte”字符串。

抛出标准异常

只需要一个string参数,它将成为被what()传回的描述字符串。例如:

namespace std {

class logic_error : public exception {

public:

explicit logic_error(const string& whatString);

};

}

提供这种功能的标准异常有:logic_error及其衍生类、runtime_error及其衍生类、ios_base::failure。你不能抛出exception,也不能抛出任何用以语言核心性质的异常。

想要抛出一个标准异常,只需要生成一个描述异常的字符串,并将它初始化,交给异常物件:

std:string s;

...

throw std::out_of_range(s);

由于char*可被隐式转换为string,所以你可以直接使用字符串字面常数:

throw std::out_of_range("out_of_range (somewhere, somehow)" );

从标准异常类(Exception Classes)中派生新类

由于what()是个虚函数,所以可以自己实现what()

namespace MyLib {

class MyProblem : public std::exception {

public:

...

virtual const char* what() const throw() { // what() function

...

}

};

void f() {

...

// create an exception object and throw it

throw MyProblem(...);

...

}

}

what()的另一种方法:

namespace MyLib {

class MyRangeProblem : public std::out_of_range {

public:

MyRangeProblem( const string& whatString )

: out_of_range(whatString) {

}

};

void f(){

throw MyRangeProblem("here is my special range problem");

}

}

配置器(allocators

(源自:百度百科)

提供了类型化的内存分配以及对象的分配和撤销。

allocator类将对象分配和对象构造分开。当allocator对象分配内存的时候,它会分配适当大小并排列成保存给定类型对象的空间。

原创粉丝点击