Loading

《C++ Primer》笔记 第5章 语句

  1. 空块的作用等价于空语句。
  2. case标签必须是整型常量表达式,default也是一种特殊的case标签。
  3. 标签不应该孤零零地出现,它后面必须跟上一条语句或者另外一个case标签。
  4. 如果在某处一个带有初值的变量位于作用域之外,在另一处该变量位于作用域之内,则从前一处跳转到后一处的行为是非法行为。不允许跨过变量的初始化语句直接跳转到该变量作用域内的另一个位置。
      case true:
            // 因为程序的执行流程可能绕开下面的初始化语句,所以该switch语句不合法
            string file_name; // 错误:控制流绕过一个隐式初始化的变量
            int ival = 0; // 错误:控制流绕过一个显式初始化的变量
            int jval; // 正确:因为jval没有初始化
            break;
      case false:
            // 正确:jval虽然在作用域内,但是它没有被初始化
            jval = next_num(); // 正确:给jval赋一个值
            if (file_name.empty()) // file_name在作用域内,但是没有被初始化
                  // ...
    
  5. 如果需要为某个case分支定义并初始化一个变量,我们应该把变量定义在块内,从而确保后面的所有case标签都在变量的作用域之外(变量的作用域在花括号内)。
      case true:
            {
                  // 正确:声明语句位于语句块内部
                  string file_name = get_file_name();
                  // ...
            }
            break;
      case false:
            if (file_name.empty()) // 错误:file_name不在作用域之内
    
  6. 定义在while条件部分或者while循环体内的变量每次迭代都经历从创建到销毁的过程(while内定义的变量只在while内有效)。
  7. 牢记for语句头中定义的对象只在for循环体内可见。
  8. do-while:作为循环的条件,不能定义在do的内部
  9. 不要在程序中使用goto语句,因为它使得程序既难理解又难修改。
  10. 标签标志符独立于变量或其它标志符的名字,因此,标签标志符可以和程序中其他实体的标志符使用同一个名字而不会相互干扰。goto语句和控制权转向的那条带标签的语句必须位于同一个函数之内
  11. 和switch语句类似,goto语句也不能将程序的控制权从变量的作用域之外转移到作用域之内:
      // ...
      goto end;
      int ix = 10; // 错误:goto语句绕过了一个带初始化的变量定义(此处是ix作用域开始的地方)(如果写成`int ix;`正确)
      end:
      // 错误:此处的代码需要使用ix,但是goto语句绕过了它的声明
      ix = 42;
    
  12. 向后跳过一个已经执行的定义是合法的。跳回到变量定义之前意味着系统将销毁该变量,然后重新创建它。
      // 向后跳过一个带初始化的变量定义是合法的
      begin:
            int sz = get_size();
            if (sz <= 0)
            {
                  goto begin;
            }
    
  13. throw表达式,异常检测部分使用throw表达式来表示它遇到了无法处理的问题。我们说throw引发了异常。例:throw runtime_error("Data must refer to same ISBN");
  14. try语句块,异常处理部分使用try语句块处理异常。try语句块以关键字try开始,并以一个或多个catch子句结束。try语句块中代码抛出的异常通常会被某个catch子句处理。因为catch子句“处理”异常,所以它们也被称作异常处理代码。
  15. 一套异常类,用于在throw表达式和相关的catch子句之间传递异常的具体信息。
  16. try语句块内声明的变量在块外部无法访问,特别是在catch子句内也无法访问(作用域仅限在该花括号内)。
      while (cin >> item1 >> item2)
      {
            try
            {
                  // 执行添加两个Sales_item对象的代码
                  // 如果添加失败,代码抛出一个runtime_error异常
            }
            catch(runtime_error err)
            {
                  // 提醒用户两个ISBN必须一致,询问是否重新输入
                  cout << err.what();
                        << "\nTry Again? Enter y or n" << endl;
                  char c;
                  cin >> c;
                  if (!cin || c == 'n')
                        break; // 跳出while循环
            }
      }
    
  17. 寻找处理代码的过程与调用链刚好相反。当异常被抛出时,首先搜索抛出该异常的函数。如果没找到匹配的catch子句,终止该函数、并在调用该函数的函数中继续寻找。如果还是没有找到匹配的catch子句,这个新的函数也被终止,继续搜索调用它的函数。以此类推,沿着程序的执行路径逐层回退,直到找到适当类型的catch子句为止。如果最终还是没能找到任何匹配的catch子句,程序转到名为terminate的标准库函数。该函数的行为与系统有关,一般情况下,执行该函数将导致程序非正常退出。对于那些没有任何try语句块定义的异常,也按照类似的方式处理:毕竟,没有try语句块也就意味着没有匹配的catch子句。如果一段程序没有try语句块且发生了异常,系统会调用terminate函数并终止当前程序的执行。
  18. 异常中断了程序的正常流程。
  19. 我们只能以默认初始化的方式初始化exceptionbad_allocbad_cast对象,不允许为这些对象提供初始值。其他异常类型的行为则恰好相反:应该使用string对象或者C风格字符串初始化这些类型的对象,但是不允许使用默认初始化的方式。当创建此类对象时,必须提供初始值,该初始值含有错误相关的信息。
posted @ 2021-01-19 21:49  橘崽崽啊  阅读(110)  评论(0编辑  收藏  举报