SovranCode
Modern C++ Lesson 04
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++ Hello World: Your First Program Explained
NEXT LESSONC++ Debugging: Warnings and Breakpoints
C++ foundations · Lesson 04 About 50 min with practice

How to Compile and Run C++ Programs

Understand C++ preprocessing, compilation, linking and execution. Build object files, diagnose missing definitions, and avoid stale executables.

Before you begin

Complete compiler setup and Hello World. The object-file lab requires your configured local toolchain; browser examples model only the small program behavior.

What you will learn

  • Distinguish source, preprocessed text, object code and executables.
  • Use a compile-only command and a separate link command.
  • Classify syntax, linker and runtime problems.
  • Explain declarations versus missing definitions.
  • Prevent a failed rebuild from being mistaken for a successful new run.

One command can perform several jobs

A command such as g++ main.cpp -o hello is convenient, but it hides intermediate work. Source must be prepared, translated for a target, and combined with required definitions before an executable can run. Understanding those jobs gives error messages a location in the workflow. You no longer need to treat every failed build as an unexplained complaint from one mysterious compiler button.

The .cpp file is editable source. An object file such as main.o contains translated code and information used by the linker; it is normally not a standalone program you launch. The final executable combines the required pieces for a selected platform. A file extension is a useful convention, not a substitute for understanding the artifact's role. Windows toolchains commonly use .obj and .exe instead of .o and an extensionless executable.

main.cpp becomes preprocessed text, then assembly and object code; linking combines object files and libraries into an executable; running is a separate stage. A missing declaration is a compile problem; a missing used definition is a link problem.
Follow the artifact at each boundary. An object file and an executable are not interchangeable.

Preparation and translation are not execution

Preprocessing handles directives such as include before the compiler translates the resulting source. Including a header makes declarations available; it does not run the header's contents as an application script. You can inspect preprocessed text with a toolchain option, but it will often be much larger than your original file because standard headers bring in substantial declarations. Size alone is not evidence of a faulty build.

Compilation checks the prepared source and translates it toward target code. Assembly, where exposed separately by the toolchain, produces object code from assembly representation. GCC's -E, -S and -c options let you stop at different points. These names are useful for investigation, not instructions to hand-run every phase for ordinary work. For this lesson, separating compile-only from link gives enough visibility to understand common failures.

A language-mode option belongs in each translation command. If one file is compiled under different assumptions from another, a later successful link does not establish that the whole program used the intended configuration. Keep the same compiler and baseline throughout the experiment. Reproducible builds record both the commands and the input files, not just the final executable's name.

Object files can become stale too. Editing greeting.cpp and relinking the unchanged greeting.o does not translate the new function body. Recompile each changed source before linking its object. Likewise, do not combine two object files that both define main and expect the linker to choose the right one: a program needs one entry definition. Keep this experiment in its own folder so unrelated exercises cannot accidentally become link inputs.

C++ PRACTICE RUNNER

Verify the source you actually built

Change buildNumber to 2 and run. Repeat the change locally; the local executable should change only after rebuilding successfully.

#include <iostream>

int main() {
    const int buildNumber{1};
    std::cout << "Build: " << buildNumber << '\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
Build: 1

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

LOCAL TERMINAL COMMANDS

Compile first, then link

Save the marker source as main.cpp. On macOS use clang++ in place of g++ in each command. These are local shell commands, not browser execution.

GCC / Clang-style workflow:
g++ -std=c++20 -Wall -Wextra -Wpedantic -c main.cpp -o main.o
g++ main.o -o hello
./hello

MSVC Developer Command Prompt:
cl /std:c++20 /EHsc /W4 /c main.cpp /Fo:main.obj
cl main.obj /Fe:hello.exe
hello.exe

A declaration can compile without supplying a definition

A declaration tells the compiler enough to check a use of a name. A function declaration specifies what can be called and the relevant types. A definition supplies the function body. If your program calls a declared function, translating that call does not necessarily require its body to be in the same source file. The linker later needs the actual definition to complete the program.

That separation enables multi-file programs, but it also explains a common failure: a valid call compiles, then the link reports an unresolved or undefined symbol. The solution is not to add a random header until the message disappears. Check that the matching definition exists and that its object file is included in the link. Names, parameter types and namespaces must match the declaration; similar wording is not enough.

The next example intentionally introduces one small function before the dedicated functions lesson. Treat int greetingCount() as a promise to return an integer and greetingCount() as a call to that promised function. You do not need to master function design yet. The example's purpose is to reveal the boundary between knowing how to check a call and having code available to execute it.

C++ PRACTICE RUNNER

Experiment: a declared but undefined function

Save as main.cpp. Compile-only should succeed; linking this file alone should fail because greetingCount has no definition. Run in the compiler-backed editor to observe the single-file link failure; the multi-file repair below needs your local toolchain.

#include <iostream>
int greetingCount();
int main() {
    std::cout << greetingCount() << '\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.

C++ SOURCE · LOCAL COMPILER

Provide the missing definition

greeting.cpp

Save this separate source as greeting.cpp. Its name and signature match the declaration in main.cpp.

int greetingCount() {
    return 3;
}
LOCAL TERMINAL COMMANDS

Build both translation units

A successful final link includes both object files. The expected program output is 3 followed by a newline.

GCC / Clang-style commands:
g++ -std=c++20 -Wall -Wextra -Wpedantic -c main.cpp -o main.o
g++ -std=c++20 -Wall -Wextra -Wpedantic -c greeting.cpp -o greeting.o
g++ main.o greeting.o -o hello
./hello

MSVC Developer Command Prompt:
cl /std:c++20 /EHsc /W4 /c main.cpp greeting.cpp
cl main.obj greeting.obj /Fe:hello.exe
hello.exe

Classify the first useful failure

A missing semicolon or an unknown variable is a source translation problem. A missing called definition is typically a link problem. A nonexistent executable path is a launch problem. A wrong calculation after launch is a behavior problem. Use that classification to choose evidence: inspect syntax for the first, linked inputs for the second, paths for the third, and values and rules for the fourth.

Diagnostics vary by toolchain and version. Do not memorize an exact sentence as the only sign of an error. Preserve the command and the first meaningful message, then express the cause in your own words. A long list of later errors may cascade from one missing boundary. Fix the smallest identified cause and rebuild before trying to interpret the entire list as independent defects.

Compile-only success proves less than a completed build, and a completed build proves less than correct behavior. Keep those claims separate in lab notes. Reaching an executable is a milestone in the workflow, not a certificate that every input is valid, the application is safe, or its output meets the requirement. The debugging lesson next uses this distinction to investigate a program that builds cleanly but computes the wrong answer.

Do not let an old executable masquerade as a new result

After a successful build, deliberately remove a semicolon and try to rebuild. The old executable may still be present. If you launch it, its output belongs to the previous source, not the broken source. Checking that a binary exists is therefore weaker than checking the current command succeeded. On a POSIX shell, chaining a build and run with && prevents the second command from running when the first fails.

The same principle applies to editor tasks: the debugger's program path must match the executable produced by the build, and the build task must complete successfully before launch. Keep source and generated outputs distinct. Do not delete arbitrary folders to resolve confusion; identify the exact artifact and command first. Later CMake lessons organize these decisions into a reusable build system.

APPLY THE CONCEPT

Independent lab

Produce a build-stage notebook: show a syntax failure, a successful compile-only step, a missing-definition link failure, and a repaired two-file executable.

Acceptance checklist

  • Use the two source files above and record the exact commands.
  • Demonstrate that main.o or main.obj is not the final executable.
  • Capture the missing-definition linker diagnostic without fabricating its wording.
  • Link both objects and verify output 3.
  • Explain why launching a previous binary after a failed rebuild is not a valid new test.
Need a hint?
  1. A declaration alone is enough to check this call during compilation.
  2. The link command must include greeting.o or greeting.obj.
  3. Use a source marker when checking whether a run belongs to a new build.
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.

// main.cpp
#include <iostream>
int greetingCount();
int main() {
    std::cout << greetingCount() << '\n';
    return 0;
}

// greeting.cpp (save in a separate file)
int greetingCount() {
    return 3;
}
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

3

Save the two labeled parts as separate files, compile each, and link both objects using the documented commands. Do not treat the display as one browser-runnable file.

The declaration permits the call to be checked; greeting.cpp supplies the definition needed by the linker.

Record actual diagnostics from your environment. The evidence is the stage and cause, not whether your message matches a screenshot word for word.

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 source, preprocessed text, object code and executables.
  • Use a compile-only command and a separate link command.
  • Classify syntax, linker and runtime problems.
  • Explain declarations versus missing definitions.
  • Prevent a failed rebuild from being mistaken for a successful new run.

References and further reading

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

  • GCC: stages and output options
  • Clang compiler manual
  • Microsoft: compiler options
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.

01What does a GCC/Clang -c command omit?
02A declared function is called, but no definition is linked. Where is the likely failure?
03A binary exists after a failed rebuild. What can you conclude?
04What does including a standard header do here?
05Which check is still needed after successful compilation and linking?
PREVIOUS LESSONC++ Hello World: Your First Program Explained
NEXT LESSONC++ Debugging: Warnings and Breakpoints
ON THIS PAGELearning objectivesOne command can perform several jobsPreparation and translation are not executionA declaration can compile without supplying a definitionClassify the first useful failureDo not let an old executable masquerade as a new resultIndependent labReviewKnowledge checkReferences
Course overview