您的位置:首页 > 编程语言 > C语言/C++

C++ 语句

2015-11-24 21:43 351 查看
《C++ Primer 4th》读书笔记

使用空语句时应该加上注释,以便任何读这段代码的人都知道该语句是有意省略的。

复合语句,通常被称为块,是用一对花括号括起来的语句序列(也可能是空的)。块标识了一个作用域,在块中引入的名字只能在该块内部或嵌套在块中的子块里访问。通常,一个名字只从其定义处到该块的结尾这段范围内可见

对象或类的定义或声明也是语句。尽管定义语句这种说法也许更准确些,但定义语句经常被称为声明语句。所以在类定义语句后需要加上分号。

switch

存在一个普遍的误解:以为程序只会执行匹配的 case 标号相关联的语句。实际上,程序从该点开始执行,并跨越 case 边界继续执行其他语句,直到 switch 结束或遇到 break 语句为止。对于 switch 结构,漏写 break 语句是常见的程序错误。

尽管没有严格要求在 switch 结构的最后一个标号之后指定 break 语句,但是,为了安全起见,最好在每个标号后面提供一个 break 语句,即使是最后一个标号也一样。如果以后在 switch 结构的末尾又需要添加一个新的 case 标号,则不用再在前面加 break 语句了。

故意省略 case 后面的 break 语句是很罕见的,因此应该提供一些注释说明其逻辑。

哪怕没有语句要在 default 标号下执行,定义default 标号仍然是有用的。定义 default 标号是为了告诉它的读者,表明这种情况已经考虑到了,只是没什么要执行的。

case 标号必须是整型常量表达式(第 2.7 节)。例如,下面的标号将导致编译时的错误:

// illegal case label values

case 3.14: // noninteger

case ival: // nonconstant

如果两个 case 标号具有相同的值,同样也会导致编译时的错误。

对于 switch 结构,只能在它的最后一个 case 标号或 default 标号后面定义变量:

case true:

// error: declaration precedes a case label

string file_name = get_file_name();

break;

case false:

// ...

制定这个规则是为避免出现代码跳过变量的定义和初始化的情况。

while

在循环条件中定义的变量在每次循环里都要经历创建和撤销的过程。

C++ 程序员应尝试编写简洁的表达式。

*dest++ = *source++;

是一个经典的例子。这个表达式等价于:

{

*dest = *source; // copy element

++dest; // increment the pointers

++source;

}

for

省略 condition,则等效于循环条件永远为 true:

for (int i = 0; /* no condition */ ; ++i)

相当于程序写为:

for (int i = 0; true ; ++i)

可以在 for 语句的 init-statement 中定义多个对象;但是不管怎么样,该处只能出现一个语句,因此所有的对象必须具有相同的一般类型:

const int size = 42;

int val = 0, ia[size];

// declare 3 variables local to the for loop:

// ival is an int, pi a pointer to int, and ri a reference to int

for (int ival = 0, *pi = ia, &ri = val;

ival != size;

++ival, ++pi, ++ri)

// …

do while

do

statement

while (condition);

与 while 语句不同。do-while 语句总是以分号结束。任何在循环条件中引用变量都必须在 do 语句之前就已经存在。

try 块和异常处理

C++ 的异常处理中包括:

1. throw 表达式,错误检测部分使用这种表达式来说明遇到了不可处理的错误。可以说,throw 引发了异常条件。

2. try 块,错误处理部分使用它来处理异常。try 语句块以 try 关键字开始,并以一个或多个 catch 子句结束。在 try 块中执行的代码所抛出(throw)的异常,通常会被其中一个 catch 子句处理。由于它们“处理”异常,catch 子句也称为处理代码。

3. 由标准库定义的一组 异常类,用来在 throw 和相应的 catch 之间传递有关的错误信息。

用 throw 抛出异常来改写检测代码:

// first check that data is for the same item

if (!item1.same_isbn(item2))

throw runtime_error("Data must refer to same ISBN");

// ok, if we're still here the ISBNs are the same

std::cout << item1 + item2 << std::endl;

try 块的通用语法形式是:

try {

program-statements

} catch (exception-specifier) {

handler-statements

} catch (exception-specifier) {

handler-statements

} //…

每个 catch 子句包括三部分:关键字 catch,圆括号内单个类型或者单个对象的声明——称为异常说明符,以及通常用花括号括起来的语句块。

每一个标准库异常类都定义了名为 what 的成员函数。这个函数不需要参数,返回 C 风格字符串。

标准库异常类定义在四个头文件中:

1. exception 头文件定义了最常见的异常类,它的类名是 exception。这个类只通知异常的产生,但不会提供更多的信息。

2. stdexcept 头文件定义了几种常见的异常类

3. new 头文件定义了 bad_alloc 异常类型,提供因无法分配内在而由 new抛出的异常。

4. type_info 头文件定义了 bad_cast 异常类型,这种类型将第 18.2 节讨论。

在<stdexcept> 头文件中定义的标准异常类

exception

最常见的问题。

runtime_error

运行时错误:仅在运行时才能检测到问题

range_error

运行时错误:生成的结果超出了有意义的值域范围

overflow_error

运行时错误:计算上溢

underflow_error

运行时错误:计算下溢

logic_error

逻辑错误:可在运行前检测到问题

domain_error

逻辑错误:参数的结果值不存在

invalid_argument

逻辑错误:不合适的参数

length_error

逻辑错误:试图生成一个超出该类型最大长度的对象

out_of_range

逻辑错误:使用一个超出有效范围的值

异常类型只定义了一个名为 what 的操作。这个函数不需要任何参数,并且返回 const char* 类型值。what 函数所返回的指针指向 C 风格字符数组的内容,这个数组的内容依赖于异常对象的类型。对于接受 string 初始化式的异常类型,what 函数将返回该 string 作为 C 风格字符数组。对于其他异常类型,返回的值则根据编译器的变化而不同。

使用预处理器进行调试

可使用 NDEBUG 预处理变量实现有条件的调试代码:

int main()

{

#ifndef NDEBUG

cerr << "starting main" << endl;

#endif

// ...

默认情况下,NDEBUG 未定义,这也就意味着必须执行 #ifndef 和 #endif之间的代码。开发完成后,要将程序交付给客户时,可通过定义 NDEBUG 预处理变量,(有效地)删除这些调试语句。大多数的编译器都提供定义 NDEBUG 命令行选项:

$ CC -DNDEBUG main.C

预处理器还定义了其余四种在调试时非常有用的常量:

__FILE__ 文件名

__LINE__ 当前行号

__TIME__ 文件被编译的时间

__DATE__ 文件被编译的日期

可使用这些常量在错误消息中提供更多的信息:

if (word.size() < threshold)

cerr << "Error: " << _ _FILE_ _

<< " : line " << _ _LINE_ _ << endl

<< " Compiled on " << _ _DATE_ _

<< " at " << _ _TIME_ _ << endl

<< " Word read was " << word

<< ": Length too short" << endl;

另一个常见的调试技术是使用 NDEBUG 预处理变量以及 assert 预处理宏。assert 宏是在 cassert 头文件中定义的,所有使用 assert 的文件都必须包含这个头文件。

预处理宏有点像函数调用。assert 宏需要一个表达式作为它的条件:

assert(expr)

只要 NDEBUG 未定义,assert 宏就求解条件表达式 expr,如果结果为false,assert 输出信息并且终止程序的执行。如果该表达式有一个非零(例如,true)值,则 assert 不做任何操作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: