SovranCode
Modern C++ Lesson 20
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 LESSONC++ Range-Based For Loop and Iterators
NEXT LESSONC++ Structs and enum class Explained
C++ foundations · Lesson 20 About 50 min with practice

C++ Vector Practice: Build a Data Summary

Build a tested C++ vector data-summary program with validated input, separate functions, bounded arithmetic, minimum, maximum, mean and explicit empty handling.

Before you begin

Complete functions, integer conversions, validated input, vector and range-based traversal. This applied lesson combines those tools rather than introducing a new container.

What you will learn

  • Separate parsing, storage, calculation and output responsibilities.
  • Specify empty-summary behavior before reading the first element.
  • Use bounded sums and floating division for a meaningful mean.
  • Keep extrema correct for negative and repeated readings.
  • Validate the design with discriminating boundary-case transcripts.

A sequence-summary program starts with a contract

A useful report needs more than a loop that happens to add some numbers. Decide which input is accepted, what each reported field means, and what happens when no records are present. This lab accepts a count from zero through eight followed by that many integer readings from minus one hundred through one hundred. Each required record occupies one complete line. There is one report per execution, not an unbounded streaming session.

The output contains count and sum for every accepted collection. A nonempty collection also has a minimum, maximum and arithmetic mean displayed with two decimal places. An empty collection instead prints No readings after its zero count and zero sum. It does not claim a minimum of zero, a maximum of zero or a mean of zero, because those labels would conceal the absence of data rather than explain it.

Write these rules before choosing function names. They decide which states your code must represent and which tests should fail. The lab is not a statistics package: it does not infer missing samples, estimate uncertainty, reject outliers or measure a physical unit. Integer readings and a small explicit bound keep the application understandable while still requiring careful reasoning about empty input, negative values and arithmetic conversion.

Required input lines are parsed and validated before entering an owning vector. Successful collection flows to total and extrema calculations, then formatting. Invalid input exits before reporting, and the empty-vector branch reports absence without reading a first element.
Keep input failure, empty data, calculation and presentation as distinct paths.

Separate collection, calculation and presentation

A parser should answer whether a complete line contains one valid integer representation. The collector adds the application's count and reading bounds. A calculation function should receive accepted data rather than reading from std::cin itself. Presentation writes the chosen labels and formatting. These responsibilities may live in one source file at this stage; separation is about contracts and dependencies, not automatically creating a new class or file for every small operation.

Pass the vector to a read-only calculation function as const std::vector<int>&. The reference avoids copying the entire collection for each query, while const prevents modification through that parameter. A function that returns an integer sum can be tested with an already constructed vector, independent of terminal parsing. That makes it easier to locate a failure: a wrong total in a pure calculation is not an input-buffer problem.

Keep this design proportional to the task. The reference solution extracts totalOf but leaves a short validated collection phase and explicit report branching in main. There is no need to introduce a general framework before the class lessons. As the application grows, a structured summary result can group related fields. For now, named local values, a clear empty guard and one focused calculation function make the information flow reviewable.

C++ PRACTICE RUNNER

Test a calculation without terminal input

The function observes its vector and returns a bounded sum. Its behavior does not depend on cin, cout or a hidden mutable global.

#include <iostream>
#include <vector>
int totalOf(const std::vector<int>& values) {
    int total{};
    for (int value : values) total += value;
    return total;
}
int main() {
    std::cout << "Empty: " << totalOf({}) << '\n';
    std::cout << "Mixed: " << totalOf({-4, 1, 3}) << '\n';
}
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
Empty: 0
Mixed: 0

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

Initialize extrema from data, not an invented neutral value

Zero is an identity for addition, but it is not a universal starting minimum or maximum. If every reading is negative, starting maximum at zero produces a value that never appeared in the data. If every reading is positive, starting minimum at zero makes the same mistake in the opposite direction. Once you know the vector is nonempty, initialize both extrema from its first actual element and then compare accepted values.

The empty check must precede front(). A variable holding a default zero cannot turn a nonexistent element into a valid observation. In the reference solution, the empty branch prints its explicit absence label and returns before either extremum is initialized from data. This makes the precondition visible in control flow. You can then review the remaining branch with the established fact that at least one reading exists.

Repeated extrema do not need special treatment: comparing equal values leaves the same minimum or maximum in place. A single reading supplies both extrema and its own mean. Test all-negative, all-positive, repeated and single-value collections because each targets a distinct assumption. A mixture containing zero would not expose every faulty zero-initialization strategy, so it is a weak sole test even when its final report looks reasonable.

C++ PRACTICE RUNNER

Trace an all-negative collection

Starting from the first accepted reading avoids inventing a maximum of zero.

#include <iostream>
#include <vector>
int main() {
    const std::vector<int> values{-8, -3, -5};
    if (values.empty()) { std::cout << "No readings\n"; return 0; }
    int minimum = values.front();
    int maximum = values.front();
    for (int value : values) {
        if (value < minimum) minimum = value;
        if (value > maximum) maximum = value;
    }
    std::cout << "Min: " << minimum << "\nMax: " << maximum << '\n';
}
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
Min: -8
Max: -3

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

Bound the sum and convert before dividing

Eight readings between minus one hundred and one hundred constrain the sum to the interval from minus eight hundred through eight hundred. An int accumulator is sufficient for that declared contract. Passing arbitrary unbounded data to the same helper would require a different arithmetic analysis. Using a vector or a const reference does not prevent integer overflow; the accepted values and count establish the bound, not the container syntax.

The arithmetic mean requires floating division when a fractional result matters. Convert the sum to double before dividing by the count, and make the count conversion explicit as well. Converting an already truncated integer quotient afterwards cannot restore its discarded fraction. The empty branch prevents division by zero before any conversion is attempted. Keep these two proofs separate: nonzero denominator and intended arithmetic type solve different problems.

Use std::fixed with std::setprecision(2) to define the display contract rather than relying on the stream's default representation. This rounds the displayed result; it does not make binary floating-point exact decimal arithmetic. Avoid presenting a temperature or monetary precision guarantee the program does not provide. The lab prints a simple numeric demonstration in the default stream locale and keeps exact integer count, sum and extrema alongside the formatted mean.

Reject partial input and preserve evidence of the first failure

If a required line is missing or malformed, print Invalid input and return status one without a summary. Reading only the valid prefix of 12abc would make the report appear more complete than it is. Parse an integer, consume trailing whitespace, and require end-of-line. A final valid line does not need a newline character after it. Extra lines after all requested records remain outside this single-report protocol and are not silently counted as additional readings.

Build a small test matrix whose cases answer different questions. Count zero checks the absence branch; a single negative value checks extrema; two readings with a fractional mean check conversion; repeated values check stable comparisons; eight endpoint values check accepted bounds. Add an overflowing integer token, a negative count, a count above eight, an invalid reading, a numeric suffix and early end-of-input to verify rejection happens before success output.

A repair exercise is to intentionally calculate the mean with integer division in your own copy, observe the failure on readings one and two, then restore conversion before division. Another is to initialize maximum to zero and test an all-negative collection. Keep the failed prediction, actual transcript and corrected reasoning in your lab notes. These are deterministic logic defects; do not introduce undefined behavior just to manufacture a debugging demonstration.

LOCAL TERMINAL COMMANDS

Compile and test outside the lesson

The compiler-backed editors support complete single-file programs when the execution service is available. Otherwise save one program as main.cpp and run these commands with your configured compiler. Supply all standard input before Run; this is not an interactive terminal.

macOS / Linux (choose your installed compiler):
clang++ -std=c++20 -Wall -Wextra -Wpedantic main.cpp -o lesson
# Or: g++ -std=c++20 -Wall -Wextra -Wpedantic main.cpp -o lesson
./lesson

Windows Developer Command Prompt:
cl /std:c++20 /EHsc /W4 main.cpp /Fe:lesson.exe
lesson.exe
APPLY THE CONCEPT

Independent lab

Build a complete reading report with validated collection, a pure total function and an explicit empty-data branch.

Acceptance checklist

  • Read a count from 0 through 8 and that many integer lines in -100 through 100.
  • Reject malformed, missing and out-of-range required input with Invalid input and status 1 before any summary.
  • Use a const-reference total function with no terminal I/O.
  • Print Count and Sum, then No readings for empty data; otherwise print Min, Max and Mean.
  • Initialize extrema from actual data and display floating mean to two decimal places.
Need a hint?
  1. Prove values is nonempty before using front or dividing by size.
  2. Test all-negative readings to expose a fictional zero maximum.
  3. Convert sum before division; 1 and 2 should have mean 1.50.
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>
#include <sstream>
#include <string>
bool readInteger(int& value) {
    std::string line;
    if (!std::getline(std::cin, line)) return false;
    std::istringstream parser{line};
    if (!(parser >> value)) return false;
    parser >> std::ws;
    return parser.eof();
}
#include <iomanip>
#include <vector>
int totalOf(const std::vector<int>& values) {
    int total{};
    for (int value : values) total += value;
    return total;
}
int main() {
    int count{};
    if (!readInteger(count) || count < 0 || count > 8) {
        std::cout << "Invalid input\n"; return 1;
    }
    std::vector<int> values;
    for (int i = 0; i < count; ++i) {
        int value{};
        if (!readInteger(value) || value < -100 || value > 100) {
            std::cout << "Invalid input\n"; return 1;
        }
        values.push_back(value);
    }
    const int sum = totalOf(values);
    std::cout << "Count: " << values.size() << "\nSum: " << sum << '\n';
    if (values.empty()) { std::cout << "No readings\n"; return 0; }
    int minimum = values.front();
    int maximum = values.front();
    for (int value : values) {
        if (value < minimum) minimum = value;
        if (value > maximum) maximum = value;
    }
    const double mean = static_cast<double>(sum) / static_cast<double>(values.size());
    std::cout << "Min: " << minimum << "\nMax: " << maximum << '\n';
    std::cout << "Mean: " << std::fixed << std::setprecision(2) << mean << '\n';
}
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

Count: 3
Sum: 3
Min: -4
Max: 6
Mean: 1.00

The collector establishes the count and value bounds before totalOf is used, limiting the sum's magnitude to eight hundred.

The empty branch gives absence its own output and prevents invalid first-element access and zero-denominator division.

Extrema start from real data; double conversion happens before division and formatting defines display rather than mathematical exactness.

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.

  • Separate parsing, storage, calculation and output responsibilities.
  • Specify empty-summary behavior before reading the first element.
  • Use bounded sums and floating division for a meaningful mean.
  • Keep extrema correct for negative and repeated readings.
  • Validate the design with discriminating boundary-case transcripts.

References and further reading

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

  • C++ Core Guidelines: functions and interfaces
  • C++ draft: arithmetic conversions
  • Microsoft: iomanip formatting
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 not initialize maximum to zero for every input?
02Which expression preserves a fractional mean?
03What should the empty report say about mean?
04What makes totalOf independently testable?
05Does setprecision(2) make the mean exact decimal arithmetic?
PREVIOUS LESSONC++ Range-Based For Loop and Iterators
NEXT LESSONC++ Structs and enum class Explained
ON THIS PAGELearning objectivesA sequence-summary program starts with a contractSeparate collection, calculation and presentationInitialize extrema from data, not an invented neutral valueBound the sum and convert before dividingReject partial input and preserve evidence of the first failureIndependent labReviewKnowledge checkReferences
Course overview