Chapter 10: Loops, Goto, and Exit

Null Statements

A null statement is a statement that does nothing. It is represented by a semicolon (;).

if (x > 10)
    ; // this is a null statement

Constexpr If Statements

Favor constexpr if statements over non-constexpr if statements when the conditional is a constant expression.

if constexpr (gravity == 9.8) // now using constexpr if
{
    // code
}

Switch Statements

Prefer switch statements over if-else chains when there is a choice. The type of the switch expression must be integral or enumerated.

switch (x) // x type: integral/enumerated
{
    int a; // okay: definition is allowed before the case labels
    int b{ 5 }; // illegal: initialization is not allowed before the case labels
case 1:
    int y; // okay but bad practice: definition is allowed within a case
    y = 4; // okay: assignment is allowed
    std::cout << "One";
case 2:
    { // note addition of explicit block here
        int x{ 4 }; // okay, variables can be initialized inside a block inside a case
        std::cout << x;
        break; // break instead of return
    }
case 3:
    std::cout << "Three";
    [[fallthrough]]; // intentional fallthrough, execute all future cases
default:
    std::cout << "Unknown";
    return;
}

Goto Statements

Avoid goto statements unless the alternatives are significantly worse for code readability.

Example

#include <iostream>

int main()
{
    double x{};
tryAgain: // this is a statement label
    std::cout << "Enter a non-negative number: ";
    std::cin >> x;

    if (x < 0.0)
        goto tryAgain; // this is the goto statement

    std::cout << x;
end:
    return 0;
}

Rules for Goto

goto skip;   // error: this jump is illegal because...
int x { 5 }; // this initialized variable is still in scope at statement label 'skip'
skip:
x += 3;      // what would this even evaluate to if x wasn't initialized?
return 0;

Loop Constructs

For Loop

for (int x{ 0 }, y{ 9 }; x < 10; ++x, --y)

While Loop

while (true) // infinite loop
for (;;) // infinite loop

Break vs Return in Loops

A break statement terminates the switch or loop, and execution continues at the first statement beyond the switch or loop. A return statement terminates the entire function that the loop is within, and execution continues at the point where the function was called.

Example

#include <iostream>

int breakOrReturn()
{
    while (true) // infinite loop
    {
        std::cout << "Enter 'b' to break or 'r' to return: ";
        char ch{};
        std::cin >> ch;

        if (ch == 'b')
            break; // execution will continue at the first statement beyond the loop

        if (ch == 'r')
    }

    // breaking the loop causes execution to resume here
    std::cout << "We broke out of the loop\n";

    return 0;
}

int main()
{
    int returnValue{ breakOrReturn() };
    std::cout << "Function breakOrReturn returned " << returnValue << '\n';

    return 0;
}

Exit and Abort

Using std::exit()

#include <cstdlib> // for std::exit()
#include <iostream>

void cleanup()
{
    // closing database or network connections,
    // deallocating any memory you have allocated,
    // writing information to a log file, etc…
    std::cout << "cleanup!\n";
}

int main()
{
    std::cout << 1 << '\n';
    cleanup();
    // or we can
    // register cleanup() to be called automatically when std::exit() is called
    std::atexit(cleanup); // note: we use cleanup rather than cleanup() since we're not making a function call to cleanup() right now

    // The std::exit() function does not clean up local variables in the current function or up the call stack.
    std::exit(0); // terminate and return status code 0 to operating system

    // The following statements never execute
    std::cout << 2 << '\n';

    return 0;
}

Using std::abort()

The std::abort() function causes your program to terminate abnormally. Abnormal termination means the program had some kind of unusual runtime error and the program couldn’t continue to run.

#include <cstdlib> // for std::abort()

std::abort();