SovranCode
Modern C++ Lesson 05
Course contents50 available · 0 planned

Get a program running

01 · C++ Introduction: What Is C++?02 · How to Install a C++ Compiler and Set Up Your Editor03 · C++ Hello World: Your First Program Explained04 · How to Compile and Run C++ Programs05 · C++ Debugging: Warnings and Breakpoints

Work with values and input

06 · C++ Variables: Initialization and Scope07 · C++ Data Types: int, double and Type Conversion08 · C++ const, constexpr and auto Explained09 · C++ Operators: Arithmetic, Comparison and Logic10 · C++ User Input: cin, getline and Validation

Control flow and functions

11 · C++ Conditions: if, else if and else12 · C++ Switch Statement: Cases, break and default13 · C++ For Loop: Syntax and Examples14 · C++ While and Do-While Loops: Examples15 · C++ Functions: Parameters and Return Values

Strings and sequences

16 · C++ Strings: std::string with Examples17 · C++ Vector: std::vector with Examples18 · C++ Arrays: std::array and Bounds Checking19 · C++ Range-Based For Loop and Iterators20 · C++ Vector Practice: Build a Data Summary

Model data with classes

21 · C++ Structs and enum class Explained22 · C++ Classes and Objects: Encapsulation23 · C++ Constructors and Member Initialization24 · C++ Const Member Functions and Composition25 · C++ Copying Objects and the Rule of Zero

Lifetime and resource ownership

26 · C++ Object Lifetime, Destructors and RAII27 · C++ Pointers and References: nullptr and Borrowing28 · C++ unique_ptr: Smart Pointers and Ownership29 · C++ Move Semantics: std::move vs Copying30 · C++ string_view and span: Avoid Dangling Views

Containers and algorithms

31 · C++ map vs unordered_map: Lookup and Examples32 · C++ set, queue and stack: When to Use Each33 · C++ Lambda Expressions and STL Algorithms34 · C++ sort and binary_search: Rules and Complexity35 · C++20 Ranges: Views, filter and transform

Errors, files, and interfaces

36 · C++ optional and variant Explained37 · C++ Exceptions: try, catch and Safe Cleanup38 · C++ File Handling: Read and Write Text Files39 · C++ Input Parsing and Data Validation40 · C++ Polymorphism: Virtual Functions and Interfaces

Generic programming and quality

41 · C++ Templates: Function and Class Examples42 · C++20 Concepts and Template Constraints43 · C++ Unit Testing: Normal and Boundary Cases44 · C++ Sanitizers: Find Memory and Undefined Behavior Bugs45 · C++ Performance: Benchmark Before Optimizing

Build and deliver a complete application

46 · C++ Header Files and Translation Units47 · C++ CMake Tutorial: Build an Executable48 · C++ Dependencies and CTest: Automated Tests49 · C++ Multithreading: Threads and Data Races50 · C++ Command-Line Applications: Help and Release Checks
Modern C++50 available · 0 planned

Get a program running

01 · C++ Introduction: What Is C++?02 · How to Install a C++ Compiler and Set Up Your Editor03 · C++ Hello World: Your First Program Explained04 · How to Compile and Run C++ Programs05 · C++ Debugging: Warnings and Breakpoints

Work with values and input

06 · C++ Variables: Initialization and Scope07 · C++ Data Types: int, double and Type Conversion08 · C++ const, constexpr and auto Explained09 · C++ Operators: Arithmetic, Comparison and Logic10 · C++ User Input: cin, getline and Validation

Control flow and functions

11 · C++ Conditions: if, else if and else12 · C++ Switch Statement: Cases, break and default13 · C++ For Loop: Syntax and Examples14 · C++ While and Do-While Loops: Examples15 · C++ Functions: Parameters and Return Values

Strings and sequences

16 · C++ Strings: std::string with Examples17 · C++ Vector: std::vector with Examples18 · C++ Arrays: std::array and Bounds Checking19 · C++ Range-Based For Loop and Iterators20 · C++ Vector Practice: Build a Data Summary

Model data with classes

21 · C++ Structs and enum class Explained22 · C++ Classes and Objects: Encapsulation23 · C++ Constructors and Member Initialization24 · C++ Const Member Functions and Composition25 · C++ Copying Objects and the Rule of Zero

Lifetime and resource ownership

26 · C++ Object Lifetime, Destructors and RAII27 · C++ Pointers and References: nullptr and Borrowing28 · C++ unique_ptr: Smart Pointers and Ownership29 · C++ Move Semantics: std::move vs Copying30 · C++ string_view and span: Avoid Dangling Views

Containers and algorithms

31 · C++ map vs unordered_map: Lookup and Examples32 · C++ set, queue and stack: When to Use Each33 · C++ Lambda Expressions and STL Algorithms34 · C++ sort and binary_search: Rules and Complexity35 · C++20 Ranges: Views, filter and transform

Errors, files, and interfaces

36 · C++ optional and variant Explained37 · C++ Exceptions: try, catch and Safe Cleanup38 · C++ File Handling: Read and Write Text Files39 · C++ Input Parsing and Data Validation40 · C++ Polymorphism: Virtual Functions and Interfaces

Generic programming and quality

41 · C++ Templates: Function and Class Examples42 · C++20 Concepts and Template Constraints43 · C++ Unit Testing: Normal and Boundary Cases44 · C++ Sanitizers: Find Memory and Undefined Behavior Bugs45 · C++ Performance: Benchmark Before Optimizing

Build and deliver a complete application

46 · C++ Header Files and Translation Units47 · C++ CMake Tutorial: Build an Executable48 · C++ Dependencies and CTest: Automated Tests49 · C++ Multithreading: Threads and Data Races50 · C++ Command-Line Applications: Help and Release Checks
PREVIOUS LESSONHow to Compile and Run C++ Programs
NEXT LESSONC++ Variables: Initialization and Scope
C++ foundations · Lesson 05 About 50 min with practice

C++ Debugging: Warnings and Breakpoints

Debug C++ with compiler warnings, breakpoints and value inspection. Find a wrong total, use LLDB or GDB locally, and verify the repair with test cases.

Before you begin

Know how to build and launch the intended executable. Browser practice can expose output mistakes; a local debugger is required for real stepping and breakpoints.

What you will learn

  • Distinguish diagnostics from evidence about runtime values.
  • State an expected result before investigating.
  • Build with debug information and explain a breakpoint.
  • Inspect values before and after a calculation.
  • Verify a repair with normal and boundary cases.

Begin with a discrepancy, not a guess

Suppose an item costs twelve whole currency units and a customer requests three items. Before running anything, write the expected total: thirty-six. Our program prints fifteen. That concrete discrepancy is a better starting point than 'the compiler is broken.' It identifies a requirement and an observation, and it gives the investigation a stopping condition: explain the difference and verify the corrected rule.

The example intentionally uses whole units to keep arithmetic simple; it is not a production money representation. Real prices require deliberate rounding and representation decisions. Here the task is to distinguish addition from multiplication, not to design a payment system. Limiting the question keeps debugging focused and prevents a small lesson from making unsupported claims about financial accuracy.

Write down inputs, expected output, actual output, build command and the smallest source that reproduces the issue. Do not begin by replacing several lines. If the next run changes behavior, you need to know which edit caused the change. A short evidence trail makes a solution explainable to another person and easier to test when the same mistake appears in a larger program.

Expected total is 12 times 3 equals 36. A breakpoint before the calculation reveals unitPrice 12 and quantity 3; stepping over shows total 15 from addition. The repair changes the operator, then reruns normal and boundary tests.
Observe the first incorrect value. A breakpoint supplies evidence; it does not repair the rule.
C++ PRACTICE RUNNER

A program that builds but computes the wrong total

Predict the output. Run, identify the first wrong rule, then change only the operator in the initializer.

#include <iostream>

int main() {
    const int unitPrice{12};
    const int quantity{3};
    const int total{unitPrice + quantity};
    std::cout << "Total: " << total << '\n';
    return 0;
}
TERMINAL OUTPUT
Predict the output, edit the source, then select Run code.

C++20 compiler runner: source and input are sent only when you press Run to this website's execution endpoint, not an external vendor. Local preview requires Docker and gcc:14; production requires a separately isolated execution service. Network is disabled; execution is limited to 3 seconds, compilation to 10 seconds, memory to 384 MB and output to 32 KB. Single-file programs only. Don't enter secrets. Edits reset on refresh; Copy your work to keep it.

Compare with the starter's expected output
Total: 15

After editing inputs, calculate a new prediction; this reference describes only the starter.

Warnings catch some mistakes, not every requirement

Warnings are feedback about patterns a compiler considers suspicious under the selected options. Keep useful warnings enabled from the beginning rather than waiting until a project becomes large. For GCC or Clang, this course starts with -Wall -Wextra -Wpedantic. For MSVC, the basic examples use /W4. These are different option families, not identical sets of diagnostics, and a clean build is not proof of correctness.

The wrong-total example can compile without warning because adding two integers is a valid operation. A compiler does not know the business rule you intended. Warnings can point out an unused variable or a questionable conversion while still missing a valid expression with the wrong meaning. Treat them as useful checks alongside output contracts and tests, not a replacement for reasoning about the program.

Read a warning's location and category, inspect the surrounding code, and explain why it is safe or needs repair. Avoid turning warnings off merely to obtain a clean screen. Also avoid changing correct behavior just to silence a message you have not understood. Record the decision, and keep deliberately problematic warning experiments separate from the warning-clean reference examples.

Give a local debugger the right executable

For this investigation, build with debug information and minimal optimization. The commands below use -g -O0 with GCC or Clang. Debug information maps source-level names and locations to the executable; low optimization makes early stepping easier to interpret. This is a teaching configuration, not a recommendation that every production build should disable optimization.

Save the wrong-total program as debug.cpp and build the named output. Launch that same output in the debugger. A debugger attached to an old binary can show values that do not correspond to the source currently open in your editor. If source locations look wrong, first verify the build, program path and configuration before treating the result as evidence about your latest code.

LOCAL TERMINAL COMMANDS

Build a local debugging executable

Choose g++ or clang++ as installed. On Windows, Visual Studio's Debug configuration and F10/Locals window offer the corresponding workflow; no LLDB installation is implied by using MSVC.

GCC / Clang:
clang++ -std=c++20 -Wall -Wextra -Wpedantic -g -O0 debug.cpp -o debug-demo

LLDB, where installed:
lldb ./debug-demo
breakpoint set --name main
run
next
frame variable

GDB, where installed:
gdb ./debug-demo
break main
run
next
info locals

A breakpoint stops before you inspect a state

A breakpoint requests a pause when execution reaches a location. It is not a statement added to your business calculation. Start at main, then step until the two input declarations have executed. Inspect unitPrice and quantity at that point. Variables may be unavailable or not meaningfully initialized before their declaration has run; the fact that their source text is visible does not make their future values available yet.

Before executing the total initializer, predict thirty-six. Step over that statement and inspect total: the addition produces fifteen. This is the earliest value that diverges from the rule. The output statement merely reveals it. Changing the output label would not repair the computation. Write the cause as 'the initializer adds quantity to unitPrice instead of multiplying them' so the correction has a specific justification.

Step over advances across the next source-level operation without intentionally exploring a called function's internals. Step into is useful when you need to investigate such a call. For this example, entering stream library code is a distraction. Continue resumes until another stop or completion. Source line mappings are not always one line per operation, especially after optimization; observe values rather than assuming each keypress represents exactly one C++ statement.

  • Pause at main and reach the point after input initialization.
  • Inspect both operands before the total expression.
  • Step over the calculation and compare total with your prediction.
  • Repair the source, rebuild and rerun the same test; an edit does not alter an already loaded binary.
C++ PRACTICE RUNNER

Repair the rule and verify independently

Run the repaired version. Try quantity zero and one, then explain why both expected results follow from the same multiplication rule.

#include <iostream>

int main() {
    const int unitPrice{12};
    const int quantity{3};
    const int total{unitPrice * quantity};
    std::cout << "Total: " << total << '\n';
    return 0;
}
TERMINAL OUTPUT
Predict the output, edit the source, then select Run code.

C++20 compiler runner: source and input are sent only when you press Run to this website's execution endpoint, not an external vendor. Local preview requires Docker and gcc:14; production requires a separately isolated execution service. Network is disabled; execution is limited to 3 seconds, compilation to 10 seconds, memory to 384 MB and output to 32 KB. Single-file programs only. Don't enter secrets. Edits reset on refresh; Copy your work to keep it.

Compare with the starter's expected output
Total: 36

After editing inputs, calculate a new prediction; this reference describes only the starter.

Keep a small regression checklist

For unitPrice twelve, test quantity three for thirty-six, quantity one for twelve, and quantity zero for zero. These cases show an ordinary multiplication and two simple boundaries. Negative quantities are outside this example's stated domain; identify the need for validation rather than treating a negative computed total as a supported order. Very large counts also require range decisions that this tiny fixed-input program does not implement.

A test should compare actual behavior with an independently derived expectation. Copying the program's expression into a test and calling the result expected can reproduce the same bug on both sides. Here hand-calculated small values are appropriate. In larger work, use requirements and independent reference cases. Keep the original failing case after the repair so a later edit cannot silently reintroduce it.

When a program crashes or an operation has undefined behavior, one observed run may be misleading. This lesson's wrong arithmetic is deterministic within small integer bounds and is not itself undefined behavior. Sanitizers and deeper memory debugging arrive later. Do not interpret the browser interpreter's bounds checks as a proof that an arbitrary native program is memory-safe.

Explain the repair, not just the green result

A useful debugging note contains the failing case, the first incorrect state, the responsible rule, the smallest repair and the cases rerun afterward. That makes success reviewable rather than dependent on a lucky final run. If the result still differs, repeat the evidence loop with the new observation. Adding tools can help, but the central skill is narrowing the question until a specific value or operation explains the difference.

APPLY THE CONCEPT

Independent lab

Investigate a time estimate: each session lasts twenty-five minutes and four sessions are planned. The faulty expression adds the two counts. Produce a trace and verify the corrected total.

Acceptance checklist

  • Predict the correct normal result before editing.
  • Record the faulty output from 25 + 4.
  • If using a local debugger, inspect both operands before and total after the calculation.
  • Change only the arithmetic rule and rebuild locally if applicable.
  • Test four, one and zero sessions; describe negative sessions as an invalid input requirement.
Need a hint?
  1. A label can be correct while the value inserted after it is wrong.
  2. Compare units: minutes per session multiplied by sessions gives minutes.
  3. Inspect after the initializer executes; do not read a value before it exists.
C++ PRACTICE RUNNER

Write and run your lab

Build your own solution before revealing the reference. Use the input field for normal, boundary and invalid cases; this runner executes your program but does not grade it.

#include <iostream>
#include <string>
#include <sstream>
#include <limits>

int main() {
    // Implement the acceptance checklist above.
    return 0;
}

TERMINAL OUTPUT
Predict the output, edit the source, then select Run code.

C++20 compiler runner: source and input are sent only when you press Run to this website's execution endpoint, not an external vendor. Local preview requires Docker and gcc:14; production requires a separately isolated execution service. Network is disabled; execution is limited to 3 seconds, compilation to 10 seconds, memory to 384 MB and output to 32 KB. Single-file programs only. Don't enter secrets. Edits reset on refresh; Copy your work to keep it.

Your lab evidence and notes

Record predictions, actual output, commands and the cause of each repair. Code is plain text: this scratchpad does not execute or grade C++.

Loading local notes…

Review your acceptance checklist and quiz explanations before marking this lesson complete. This is self-review, not a grade or certification.

Reveal the explained lab solution
C++ PRACTICE RUNNER

Reference lab solution

Compare the reference with your own reasoning. Running this solution does not grade or complete the lesson.

#include <iostream>
int main() {
    const int minutesPerSession{25};
    const int sessions{4};
    const int totalMinutes{minutesPerSession * sessions};
    std::cout << "Minutes: " << totalMinutes << '\n';
    return 0;
}
TERMINAL OUTPUT
Predict the output, edit the source, then select Run code.

C++20 compiler runner: source and input are sent only when you press Run to this website's execution endpoint, not an external vendor. Local preview requires Docker and gcc:14; production requires a separately isolated execution service. Network is disabled; execution is limited to 3 seconds, compilation to 10 seconds, memory to 384 MB and output to 32 KB. Single-file programs only. Don't enter secrets. Edits reset on refresh; Copy your work to keep it.

Expected output

Minutes: 100

The faulty addition yields 29. The multiplication models the stated relationship and yields 100.

One session should produce 25 and zero sessions should produce 0. These independent predictions help detect the original wrong rule.

The browser can execute the small calculation; real breakpoints, stepping and locals inspection require the local debugger described above.

Review before moving on

Explain the lesson's objectives in your own words, compare your lab evidence with the acceptance checklist, and keep the first failing case alongside your repair. Completing a page is not proof that every C++ feature or input is supported.

  • Distinguish diagnostics from evidence about runtime values.
  • State an expected result before investigating.
  • Build with debug information and explain a breakpoint.
  • Inspect values before and after a calculation.
  • Verify a repair with normal and boundary cases.

References and further reading

Original examples and exercises accompany these primary references. Tool-specific diagnostics and support depend on your installed version.

  • GCC: warning options
  • LLDB tutorial
  • GDB: sample debugging session
KNOWLEDGE CHECK

Check your understanding

Answer all five questions, then review the explanations. Answers are not saved or synced; completion is a separate self-review choice.

01Why might the wrong-total program produce no compiler warning?
02When should you inspect total for this experiment?
03Which debugger action avoids intentionally entering stream library internals?
04Why use -g -O0 for the local lesson build?
05What is a useful boundary check for the repaired multiplication?
PREVIOUS LESSONHow to Compile and Run C++ Programs
NEXT LESSONC++ Variables: Initialization and Scope
ON THIS PAGELearning objectivesBegin with a discrepancy, not a guessWarnings catch some mistakes, not every requirementGive a local debugger the right executableA breakpoint stops before you inspect a stateKeep a small regression checklistExplain the repair, not just the green resultIndependent labReviewKnowledge checkReferences
Course overview