SGI STL(三)——C++ 一般概念

C++ 之一般概念(General Concepts)

  • C 之一般概念General Concepts
    • 命名空间namespace std
    • 头文件headers的名称与格式
    • 错误error和异常exception处理的一般概念
      • Standard Exception Classes标准异常类别
        • Exception Classes for Language Support语言本身支持的异常类
        • Exception Classes for Logic Errors逻辑错误异常类
        • Exception Class for Runtime Errors运行时错误异常类
        • Exceptions Thrown by the Standard Library标准程序库所抛出的异常
        • 异常类别的头文件
      • 异常类别成员
      • 抛出标准异常
      • 从标准异常类别中派生新类别

命名空间(namespace) std

  当我们采用不同的模块和程序库时,经常会出现名称冲突现象,这是因为不同模块和程序库可能针对不同的对象使用相同的标识符。namespace 可以解决这个问题,前一篇博客已有了一定介绍。namespace 可以出现在任何源码文件中,因此,可以利用 namespace 来定义一些组件,而它们可散布于多个实质模块上。这类组件的典型例子就是 C++ 标准程序库,因为 C++ 标准程序库使用了一个 namespace。事实上,C++ 标准程序库中的所有标识符都被定义于一个名为 std 的 namespace 中。
  由于 namespace 的概念,使用 C++ 标准程序库的任何标识符时,有三种选择:
  1. 直接指定标识符。例如:std::ostream,而不是ostream。完整语句类似这样:std::cout <
  2. 使用 using declaration。例如,我们增加以下片段,便不用在写出作用域修饰符 std::,而可以直接使用 cout 和 endl:using std::cout; using std::endl;,然后上面一条语句可以写成这样:cout <
  3. 使用 using directive,这是最简便的选择。如果对 namespace std 采用 using directive,便可以让 std 内定义的所有标识符都有效(曝光),就好像它们被声明为全局标识符一样。因此,写下using namespace std;之后,就可以直接写cout <注意,由于某些晦涩的重载(overloading)规则,在复杂的程序中,这种方式可能导致意外的命名冲突,更糟糕的是导致不一样的行为。如果场合不够明确(例如在头文件、模块或程序库中),就应该避免使用 using directive

头文件(headers)的名称与格式

  将 C++ 标准程序库中所有标识符都定义于 namespace std 里面,这种做法是标准化过程中引入的。这个做法不具有向下兼容性,因为原来的 C/C++ 头文件都将 C++ 标准程序库的标识符定义于全局范围(global scope)。既然有必要重新定义标准头文件的名称,正好借此机会把头文件的扩展名加以规范化。于是,便有了现在的标准头文件扩展名:根本就没有扩展名。于是,便有了这样的语句#include ,这种写法也适用于 C 标准头文件,但必须采用前缀字符 c,而不再是扩展名 .h#include // was: 。在这些头文件中,每一个标识符都被定义于 namespace std。这种命名方式的优点之一是可以区分旧文件中的 char* C 函数,和新文件中的标准 C++ string class#include // C++ class string#include // char* functions from C为了向下兼容 C,旧的 C 标准头文件仍然有效。
  注意:从操作系统角度看,新头文件命名方式并不意味着标准头文件没有扩展名。标准头文件的 #include 该如何处理,由编译器决定。一般而言,为自己写的头文件加上一个良好的扩展名,有助于轻易识别出这些文件的性质。

错误(error)和异常(exception)处理的一般概念

  C++ 标准程序库由不同的成分构成。来源不同,设计的实现风格迥异,而错误处理和异常处理正是体现这种差异的体现。标准程序库中有一部分,例如 string class,支持具体的错误处理,他们会检查所有可能发生的错误,并与错误发生时抛出异常。至于其它部分如 STL 和 valarrays,效率重于安全,因此几乎不检查逻辑错误,并且只在执行期(runtime)发生错误时才抛出异常。
SGI STL(三)——C++ 一般概念_第1张图片

Standard Exception Classes(标准异常类别)

  语言本身或标准程序库所抛出的所有异常,都派生自基类 exception。这是其它数个标准异常类别的基类,它们共同构成一个类体系。这些标准异常类可分为三组:
  1. Language support(语言本身支持的异常)
  2. Logic errors(逻辑错误)
  3. Runtime errors(运行时错误)
  我们常常可以避免逻辑错误,因为逻辑错误在程序作用域范围内,例如前提违例(precondition violation)1。由于运行时错误不在程序作用域范围内,很难被避免。

Exception Classes for Language Support(语言本身支持的异常类)

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

  • 运行时,当一个加诸与 reference 身上的”动态类型转换操作“失败时,dynamic_cast 会抛出一个 bad_cast 异常。
  • 运行期间类型辨识过程中,如果交给 typeid 的参数为零或者空指针,typeid 操作符就会抛出 bad_typeid 异常。
  • 如果发生非预期的异常, bad_exception 异常会接手处理。当函数抛出异常规格(exception specification)以外的异常,但是,C++ 11 不赞成使用。

Exception Classes for Logic Errors(逻辑错误异常类)

  C++ 标准程序库总是派生自 logic_error。从理论上讲,我们能够通过一些手段,在程序中避免逻辑错误——例如对函数参数进行额外测试等等。

  • invalid_argument 表示无效参数,例如将 bitset(array of bits)以 char 而非 ‘0’ 或 ‘1’ 进行初始化。
  • length_error 指出某个行为“可能超越了最大极限”,例如对某个字符串附加太多字符。
  • out_of_range 指出参数值“不在预期范围内”,例如在诸如 array 的容器或字符串 string 中采用一个错误索引。
  • domain_error 指出专业领域范畴内的错误。

      一般来说,逻辑错误类被定义在中,但是,类future_error被定义在

Exception Class for Runtime Errors(运行时错误异常类)

  派生自 runtime_error 的异常,用来指出“不在程序范围内,且不容易回避的事件”。C++ 标准库提供了以下 runtime errors:

  • range_error 指出内部计算时发生区间错误(range error)
  • overflow_error 指出算术运算发生上溢位(overflow)
  • underflow_error 指出算术运算发生下溢位(underflow)
  • system_error 指出底层操作系统的错误,例如并发环境(context of concurrency)
  • bad_alloc 会在操作符 new 操作失败时抛出这个异常(若采用 new 的 nothrow 版本,另当别论)。由于这个异常可能于任何时间在任何比较复杂的程序中发生,所以可以说是最重要的一个异常
  • bad_weak_ptr 在创建一个弱共享指针失败时被抛出
  • bad_function_call 在调用函数封装对象却没有目标时抛出

Exceptions Thrown by the Standard Library(标准程序库所抛出的异常)

  C++ 标准程序库可以抛出几乎所有的异常,然而,由于标准程序库会用到语言特性及客户所写的程序代码,所以也可能间接抛出任何异常。尤其是,无论何时分配存储空间,都有可能抛出 bad_alloc 异常。
  标准程序库的任何具体实作品,都可能提供额外的异常类别(或作为兄弟类别,或派生为子类别)。使用这些非标准类别将导致程序难以移植,因为一旦采用其它标准程序库版本,就不得不痛苦地修改程序。所以,最好使用标准异常。

异常类别的头文件

  异常类定义在许多不同的头文件,因此,若要处理这些程序库抛出的异常,需要包含这些头文件

#include   // for classes exception and bad_exception
#include   // for most logic and runtime error classes
#include   // for system errors
#include   // for out-of-memory exceptions
#include   // for I/O exceptions
#include   // for errors with async() and futures
#include   // for bad_cast and bad_typeid

异常类别成员

  为了在 catch 子句中处理异常,必须采用异常所提供的接口。所有标准异常接口只含有一个成员函数:waht(),用于获取“类型本身以外的附加信息”。它返回一个以 null 结束的字符串。

抛出标准异常

  你可以在自己的程序库或程序内部抛出某些标准异常,允许我们运用各个标准异常,生成时都只需要一个 string 参数,它将成为被 what() 返回的描述字符串。

从标准异常类别中派生新类别

  另一个在程序中采用标准异常类别的可能情况是,定义一个直接或间接派生自 exception 的特定异常类别。要这么做吗,首先必须要确保 what() 机制正常运作。what() 是个虚拟函数,所以提供 what() 的方法之一就是自己实现 what()。



  1. 前提违例(precondition violation):指调用一个实际上没有包含函数对象的函数对象包装类,很像试图用一个空的函数指针调用函数,并抛出一个 bad_function_call 异常。 ↩

你可能感兴趣的:(SGI-STL)