Chapter 5 Statements
5.1 Simple Statements
- An expression becomes an expression statement when it is followed by a semicolon. The result of the expression is discarded.
- The empty/null statement is a single semicolon. It is useful when a statement is required syntactically but no action is needed. They should be commented to indicate it is intentional.
- A compound statement (block) is a sequence of statements and declarations surrounded by a pair of curly braces. It is treated as a single statement. A block is not terminated by a semicolon.
- A block is a scope (section 2.2).
- An empty block is equivalent to a null statement.
5.2 Statement Scope
- We can define variables inside the control structure (condition) of
if,switch,whileandforstatements. They are visible only within that statement.- Only one variable can be defined, and it must be initialized. The variable is created and destroyed on each iteration.
while (int i = get_num())
cout << i << endl; // i is valid here
cout << i << endl; // error: i is not valid here
5.3 Conditional Statements
The if Statement
- Two forms of
if:if (condition) statementandif (condition) statement else statement. - Dangling
else: eachelseis matched with the closest preceding unmatchedif. - To avoid ambiguity, we should always use braces for
ifstatements.
The switch Statement
- The expression in the
switchstatement is converted to integral type, and the result is compared with the value associated with eachcase. breaktransfers control out of theswitch. If we omitbreak, the program will fall through the nextcaselabel.- It is recommended to include a comment explaining the fall through.
- Include a
breakafter the last label of aswitch. If an additionalcaseis added later, thebreakis already in place.
caselabels must be integral constant expressions. It is an error for any twocaselabels to have the same value.- The statements following the
defaultlabel are executed if nocaselabel matches the value.- Always define a
defaultlabel: it indicates that the case is considered.
- Always define a
- A label may not stand alone; it must precede a statement or another
caselabel.
switch (n) {
case 1:
do_something();
default: ; // null statement
}
- It is illegal to jump from a place where a variable with an initializer is out of scope to a place where that variable is in scope. If we need to define and initialize a variable for a particular
case, we can define the variable inside a block.- If the variable is not initialized, using it in another
caseis legal.
- If the variable is not initialized, using it in another
switch (n) {
case 1:
int x; // no initializer
x = 10;
break;
case 2:
x = 20; // ok: x is still in scope here
break;
}
5.4 Iterative Statements
The while Statement
- A
whileloop is generally used when we want to iterate indefinitely.
Traditional for Statement
- The
init-statementcan define several objects, but it may be only a single declaration statement - all variables of the same base type. - Any or all of
init-statement,condition, orexpressioncan be omitted.
Range for Statement
- C++11 introduced a simpler
forstatement for iterating through elements of an array/sequence (with iterators):for (declaration : expression) statement.- The expression can be a braced initializer list.
- Range
forcan be viewed as iterating using iterators returned bystd::begin()andstd::end()(more details in section 9.3).
The do while Statement
- The
do whileloop does not allow variable definitions inside the condition - it is not evaluated until after the statement is executed. - Every statement ends with a semicolon or a block - this is why a semicolon is required after the parenthesized condition.
5.5 Jump Statements
The break Statement
- A
breakstatement terminates the nearest enclosingwhile,do while,for, orswitchstatement.
The continue Statement
- A
continuestatement terminates the current iteration of the nearest enclosingwhile,do while,for, orswitchstatement and immediately begins the next iteration.- In a traditional
forloop, execution continues at theexpressioninside the header.
- In a traditional
The goto Statement
- Do not use
gotos - they make programs hard to understand and modify. goto label;jumps to a labeled statement (any statement preceded by an identifier followed by a colon).- A label may have the same identifier as another entity in the program without interference.
- Control transfer limitations:
- The
gotoand the labeled statement must be in the same function. - We cannot transfer control from a point where an initialized variable is out of scope to a point where that variable is in scope. However, backward jumping over an initialized variable definition is okay (the previous variable will be destroyed and constructed again).
- The
goto end; // error: bypass initialized ix
int ix = 10;
end:
ix = 42;
begin:
int ix = 10;
goto begin; // ok: define and initialize ix again
5.6 try Blocks and Exception Handling
- Exceptions are run-time anomalies that exist outside the normal functioning of a program. When one part of a program detects a problem it cannot solve, it signals it using exceptions without knowing what part of the program will deal with that, and stop processing. Another part of the program handles whatever happened (exception handler).
A throw Expression
throwexpressions raise exceptions:throw expression. The expression can be of any type - even an integer.- A single
throw;forwards the currently handled exception to the its external level.
The try Block
- A
tryblock begins withtryfollowed by a block. Following it is a list of one or morecatchclauses. Eachcatchconsists of three parts:catch, exception declaration, and a block.- Exception declaration can be a lvalue reference, which avoids extra copy/move. Unlike function return values, non-
constreferences are also supported - the exception object lives in special storage and behaves like an lvalue. rvalue references are not allowed. - An ellipsis (
...) can be used to catch any exception type.
- Exception declaration can be a lvalue reference, which avoids extra copy/move. Unlike function return values, non-
try {
statements
} catch (exception-declaration) {
handler-statements
} catch (exception-declaration) {
handler-statements
} // ...
- The search for a handler reverses the call chain. If no appropriate
catchis found, execution is transferred to a library functionterminateto stop the program. - Whether a handler is a match is determined by:
- The same type as the thrown object.
- The base class of the thrown object (cautious about polymorphism: pointers/references and virtual member functions should be used).
- Standard pointer conversions (e.g. array, function,
void */const void *) (section 4.11).
- Exception safe code is hard to write: we must ensure that invalid/incomplete objects and states (resulting from bypassing part of the program) need to be properly cleaned up.
Standard Exceptions
- The C++ standard library provides several classes of exceptions:
exceptiondefines the base classstd::exception.stdexceptdefines several general-purpose exception classes we can use.newdefinesstd::bad_alloc(section 12.1).type_infodefinesstd::bad_cast(section 19.2).
exception,bad_alloc, andbad_castcan only be default initialized. Other exception types can only be initialized with astringor a C-style string, which is returned by thewhatmember function.
