C++ 1.8 Tests 정리: 조건식, short-circuit, if 초기화, switch fall-through, vector::size() | slug: 20260912-cpp-1-8-tests-merged | series: A Tour of C++ 1.8

A Tour of C++ §1.8 Tests is about how C++ expresses selection and looping. You branch and repeat with if, switch, while, and for—and in every condition slot, integers, pointers, logical operators, and the ternary operator all feed the same “run this or skip it” decision.

This post merges study notes into one teaching article. It turns common mix-ups into explicit corrections: truthiness, short-circuit safety, why chained comparisons fail, when ?: helps, what the if-initializer semicolon separates, switch break versus fall-through, size() versus capacity(), plus an FAQ and a practical debugging checklist.

Key ideas: selection and loops

These constructs shape control flow:

ConstructRole
ifChoose a path from a condition
switchBranch on one of several constant values
while / forRepeat while a condition holds

I/O shows up beside them: cout << writes, cin >> reads. The type of the right-hand variable after >> decides what gets extracted. You may also declare variables at the point of need, not only at the top of a function.

What does C++ treat as true?

In a conditional context such as if, while, or the first operand of ?:, C++ converts a value to a Boolean decision.

ExpressionCondition resultMeaning
0falseZero is false.
Any non-zero integertrue1, -1, and 42 are all true.
nullptrfalseThe pointer does not point to an object.
Non-null pointertrueThe pointer contains an address that can be tested as present.
int count = 3;
if (count) {
    // runs: 3 is non-zero
}

int* p = nullptr;
if (p) {
    // does not run
}

Important: “true” does not mean the integer value is exactly 1. It means that the value converts to true in a conditional context.

Logical operators and short-circuit evaluation

&& means “both sides must be true,” and || means “at least one side must be true.” The key behavior is that evaluation may stop as soon as the result is determined.

bool is_valid = ptr != nullptr && ptr->ready();

If ptr != nullptr is false, C++ does not call ptr->ready(). This is short-circuit evaluation. It is both an optimization and a safety rule that prevents dereferencing a null pointer.

bool open = true;
if (open || expensive_check()) {
    // expensive_check() is not called
}

With ||, a true left operand already makes the entire expression true. With &&, a false left operand already makes the entire expression false.

Do not write mathematical chained comparisons

This expression looks natural if you are thinking in mathematics, but it is not a range check in C++:

if (5 < x < 20) {  // wrong
}

C++ evaluates it from left to right: 5 < x becomes true or false, which is then compared with 20. The correct range check is:

if (5 < x && x < 20) {
    // x is strictly between 5 and 20
}

The conditional operator: condition ? a : b

The conditional operator selects one of two expressions. It is useful when both branches are short and conceptually form one value.

const char* mode = hot ? "Hot" : "Normal";
int limit = enabled ? 100 : 0;

Read it as: “if hot is true, use "Hot"; otherwise use "Normal".” For multi-step logic or side effects, an ordinary if/else is usually clearer.

What is if-with-initializer?

You can create a variable inside the if and test it in the same statement:

if (auto n = v.size(); n!=0) {
    // use n
}

A frequent first reading is that both sides of the semicolon are conditions. They are not.

PartMeaning
Before ;Initialization only. Not a true/false test. It always runs.
After ;The only condition that decides whether to enter the if.

Teaching correction: In if (auto n = v.size(); n!=0), the front creates n; the back alone decides entry.

Short form: if (auto n = v.size())

With no semicolon, the value you just created is the condition. For numeric types, 0 is false and non-zero is true.

if (auto n = v.size()) {
    // same idea as n != 0 when size() yields an integer
}

v.size() is typically zero or positive. In that situation if (n) and if (n!=0) mean the same thing. Writing n!=0 is not an extra “has elements?” check beyond the short form—the short form is that check.

Use the semicolon form when the condition is not a simple non-zero test—for example n > 10:

if (auto n = v.size(); n > 10) {
    // only when the count exceeds 10
}

Scope of n

n lives in both the true and false branches of that if. After the statement ends, n is gone.

if (auto n = v.size(); n!=0) {
    // n is visible here
} else {
    // and here
}
// n is not visible here

switch and break: when does fall-through happen?

Each case label must be a distinct constant. If nothing matches and there is no default, the switch does nothing. default is optional.

Without break, execution falls through into the next case and continues until a break (or return). That can be a bug—or intentional case stacking that shares one body:

switch (ch) {
case 'u':
case 'n':
    // shared handling for 'u' and 'n'
    break;
default:
    break;
}

Remember: Fall-through means control continues downward. A return also stops further cases because the function exits.

A frequent confusion: vector::size() versus capacity

std::vector<int> v;

if (auto n = v.size()) {
    std::cout << "A";
} else {
    std::cout << "B";
}

The output is B, because an empty vector has v.size() == 0. The vector object still exists. size() is the number of elements currently stored, not whether memory has been reserved internally.

Member functionWhat it tells you
v.size()How many elements are currently in the vector.
v.capacity()How many elements can fit before a reallocation may be needed.
std::vector<int> v {10};
if (auto n = v.size()) {
    std::cout << "A";  // n is 1, so A is printed
}

Keep this sentence: An empty vector is not “a missing vector”—it is “a vector with zero elements.”

FAQ from corrected misunderstandings

Why does accept() return false for anything other than y?

It is easy to say “because it is a bool function.” That is not the reason. The logic only returns true when answer == 'y'; every other path hits return false;. So 'n' and 'x' are treated the same. Designs like the book’s accept2 can split n vs default with a switch if you need different behavior.

What if you omit break in a switch?

You get fall-through: execution continues into later cases until break or return. Stacking cases on purpose is a valid way to share behavior.

Are if (auto n = v.size(); n!=0) and if (auto n = v.size()) different?

Not in this example. For an integer size that is 0 or positive, if (n) and if (n!=0) agree. Prefer the short form for the common “non-empty” test; use init; condition when the condition is something else (e.g. n>10).

Can you use n outside the if?

No. It is available in the if’s then/else branches only.

Practical debugging mindset

When reading a condition in firmware, daemon, or application code, split it into three questions:

  1. What value does each subexpression produce?
  2. How is that value converted to true or false?
  3. Can && or || skip a later function call or access?

For example, if (device && device->is_ready()) first guards the pointer, then checks the state only when the pointer exists. The order is part of the program’s safety logic.

Summary

  • Selection and loops: if, switch, while, for.
  • 0 and nullptr are false; non-zero integers and non-null pointers are true in conditions.
  • && stops after a false left operand; || stops after a true left operand.
  • Write a range test as low < x && x < high, not low < x < high.
  • Use condition ? a : b for a small two-way value selection.
  • In if (init; cond), init always runs; only cond decides entry.
  • For integer size(), the short form matches n!=0.
  • Switch cases are distinct constants; missing break means fall-through.
  • An empty vector exists, but its size() is zero—distinct from capacity().
  • accept() rejects non-y because of its branches, not “because bool.”
  • An if-initializer variable does not leak past the if.

Next: §1.9 Mapping to Hardware

Next we will look at how these control-flow ideas map down toward the machine (§1.9 Mapping to Hardware).