Free Handbook · Every example compiled & verified

Errors & Debugging

Read compiler, linker and runtime errors the way experienced C++ developers do, fix the 15 you will hit most, and catch memory bugs with sanitizers and a debugger.

0 / 145 lessons🔥 0 day streak
ShareXLinkedIn

Module 11 · what you'll be able to do

  • Tell a compile error, a link error, a runtime exception and undefined behaviour apart, and know which tool finds each
  • Read a clang diagnostic from the first error down, and find your own line inside a template error
  • Fix the 15 errors every C++ beginner meets, from a missing semicolon to a use-after-free
  • Catch standard exceptions and print what() to see what went wrong
  • Turn on warnings and AddressSanitizer, and step through a program with lldb or gdb
01

Compile, link, run: where each error comes from

A C++ program can fail at four different moments, and the error looks completely different at each. Knowing which stage you are in is half the fix.

The last row is the dangerous one. Undefined behaviour may crash, may print garbage, or may appear to work and fail later on another machine. Sanitizers (below) turn it into a clear report.
StageWho reports itLooks likeTypical cause
CompileThe compiler (clang, gcc, MSVC)main.cpp:4:19: error: …Syntax, types, names, const, templates
LinkThe linker (ld)Undefined symbols / undefined reference toDeclared but not defined, missing library or source file
Run: exceptionThe C++ runtimeterminating due to uncaught exception of type std::out_of_rangeA thrown exception nobody caught
Run: crash or garbageThe operating system, or nobodysegmentation fault, exit 139, or wrong outputUndefined behaviour: null or dangling pointers, out-of-bounds reads
C++main.cpp
#include <iostream>

// A declaration tells the compiler a function exists; the definition gives
// the linker its body. Both must exist somewhere in the program.
double tax(double amount);

int main() {
    std::cout << tax(100.0) << '\n';
}

double tax(double amount) {
    return amount * 0.18;
}
Outputcompiled & run with real C++
18

The call in main compiles because of the declaration at the top; the program links because the definition exists below. Delete the definition and you get error 5 in this module: a link error, not a compile error.

02

Reading a compiler diagnostic

A clang diagnostic has a fixed shape: file:line:column: error: message, the offending line with a caret ^ under the exact spot, and sometimes a fix-it suggestion on the line below. Follow-up note: lines explain it: where something was declared, which overloads were tried and why each was rejected.

  1. 1
    Fix the first error first

    One mistake (a missing ; or }) can produce dozens of follow-on errors. Fix the first one, recompile, and many of the rest disappear.

  2. 2
    Read the message, then the caret

    The column number and caret usually point at the exact token. "expected ';'" with the caret after 40 means the semicolon belongs there.

  3. 3
    In template errors, find your own file

    Errors inside the standard library print pages of .../c++/v1/... paths. Scan for the note that says in instantiation of … requested here with main.cpp in it: that is the line you wrote.

  4. 4
    Read the notes on "no matching function"

    Each candidate function not viable note says exactly which argument failed and why ("no known conversion from 'std::string' to 'int' for 1st argument").

  5. 5
    Turn warnings on and treat them seriously

    Compile with -Wall -Wextra -Wpedantic. Many runtime bugs (uninitialised variables, sign comparisons, missing returns) are announced as warnings first.

bash
# the flags worth using on every build while learning
c++ -std=c++20 -Wall -Wextra -Wpedantic -g -fsanitize=address,undefined main.cpp -o prog
./prog

# release build: optimise, keep warnings, drop sanitizers
c++ -std=c++20 -Wall -Wextra -O2 main.cpp -o prog
03

Compile errors: syntax, names and types

The most common compile errors, each compiled for real. The messages are from clang; gcc and MSVC word them differently but point at the same line.

Error you will hit

1. expected ';' at end of declaration

C++
#include <iostream>

int main() {
    int total = 40
    std::cout << total << '\n';
}
main.cpp:4:19: error: expected ';' at end of declaration
    4 |     int total = 40
      |                   ^
      |                   ;
1 error generated.
Why the compiler said that

Every statement ends with a semicolon. Line breaks mean nothing to the compiler, so it reports the error at the end of line 4, where the semicolon should be, and even shows the fix-it under the caret.

The fix

Add the semicolon where the caret points. If the reported line looks fine, check the end of the line above it, and for a missing ; after a struct or class closing brace.

C++
#include <iostream>

int main() {
    int total = 40;
    std::cout << total << '\n';
}
Error you will hit

2. use of undeclared identifier 'cout'

C++
#include <iostream>

int main() {
    cout << "hello\n";
}
main.cpp:4:5: error: use of undeclared identifier 'cout'; did you mean 'std::cout'?
    4 |     cout << "hello\n";
      |     ^~~~
      |     std::cout
.../c++/v1/iostream:57:42: note: 'std::cout' declared here
   57 | extern _LIBCPP_EXPORTED_FROM_ABI ostream cout;
      |                                          ^
1 error generated.
Why the compiler said that

Everything in the standard library lives in the std namespace. The same error appears for a typo in a variable name, or for a name whose header was never included.

The fix

Write std::cout. Avoid using namespace std; at file scope in real code: it pulls hundreds of names into your scope and causes clashes. If the name really is undeclared, add the right #include.

C++
#include <iostream>

int main() {
    std::cout << "hello\n";
}
Error you will hit

3. no matching function for call

C++
#include <iostream>
#include <string>

int area(int width, int height) { return width * height; }

int main() {
    std::string w = "4";
    std::cout << area(w, 5) << '\n';
}
main.cpp:8:18: error: no matching function for call to 'area'
    8 |     std::cout << area(w, 5) << '\n';
      |                  ^~~~
main.cpp:4:5: note: candidate function not viable: no known conversion from 'std::string' (aka 'basic_string<char>') to 'int' for 1st argument
    4 | int area(int width, int height) { return width * height; }
      |     ^    ~~~~~~~~~
1 error generated.
Why the compiler said that

C++ never converts a string to a number implicitly. The note names the argument (1st) and both types, which is everything you need.

The fix

Convert explicitly with std::stoi (and handle bad input, see error 13), or pass the right type in the first place.

C++
#include <iostream>
#include <string>

int area(int width, int height) { return width * height; }

int main() {
    std::string w = "4";
    std::cout << area(std::stoi(w), 5) << '\n';
}
Error you will hit

4. cannot assign to variable with const-qualified type

C++
int main() {
    const int maxUsers = 100;
    maxUsers = 200;
    return maxUsers;
}
main.cpp:3:14: error: cannot assign to variable 'maxUsers' with const-qualified type 'const int'
    3 |     maxUsers = 200;
      |     ~~~~~~~~ ^
main.cpp:2:15: note: variable 'maxUsers' declared const here
    2 |     const int maxUsers = 100;
      |     ~~~~~~~~~~^~~~~~~~~~~~~~
1 error generated.
Why the compiler said that

const is a promise that the value never changes after initialisation, and the compiler enforces it. The same error appears when a const member function tries to modify a member, or when you write through a const& parameter.

The fix

Decide which is true: if the value must change, drop const; if it must not, the assignment is the bug.

C++
int main() {
    int maxUsers = 100;
    maxUsers = 200;
    return maxUsers;
}
Error you will hit

5. no member named 'email' in 'User'

C++
#include <string>

struct User {
    std::string name;
};

int main() {
    User u{"Asha"};
    return u.email.size();
}
main.cpp:9:14: error: no member named 'email' in 'User'
    9 |     return u.email.size();
      |            ~ ^
1 error generated.
Why the compiler said that

The type has no member with that name: a typo, a member that was renamed, or a member that belongs to a different type than you think u is.

The fix

Check the class definition. Hover the variable in your editor to confirm its type. Add the member if it should exist.

C++
#include <string>

struct User {
    std::string name;
    std::string email;
};

int main() {
    User u{"Asha", "[email protected]"};
    return u.email.size();
}
Error you will hit

6. invalid operands to binary expression (printing a struct)

C++
#include <iostream>

struct Point { int x; int y; };

int main() {
    Point p{1, 2};
    std::cout << p << '\n';
}
main.cpp:7:15: error: invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>') and 'Point')
    7 |     std::cout << p << '\n';
      |     ~~~~~~~~~ ^  ~
.../c++/v1/__ostream/basic_ostream.h:349:55: note: candidate function template not viable: no known conversion from 'Point' to 'char' for 2nd argument
.../c++/v1/__ostream/basic_ostream.h:376:53: note: candidate function template not viable: no known conversion from 'Point' to 'char' for 2nd argument
... (dozens more candidates)
Why the compiler said that

std::cout knows how to print built-in types and strings, not your types. The compiler lists every operator<< it tried; the first line is the one that matters.

The fix

Write an operator<< for your type (Module 07), or print the members yourself.

C++
#include <iostream>

struct Point { int x; int y; };

std::ostream& operator<<(std::ostream& os, const Point& p) {
    return os << '(' << p.x << ", " << p.y << ')';
}

int main() {
    Point p{1, 2};
    std::cout << p << '\n';
}
Error you will hit

7. type 'double' cannot be narrowed to 'int' in initializer list

C++
int main() {
    double price = 9.99;
    int cents{price * 100};
    return cents;
}
main.cpp:3:15: error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing]
    3 |     int cents{price * 100};
      |               ^~~~~~~~~~~
main.cpp:3:15: note: insert an explicit cast to silence this issue
    3 |     int cents{price * 100};
      |               ^~~~~~~~~~~
      |               static_cast<int>( )
1 error generated.
Why the compiler said that

Brace initialisation forbids narrowing conversions that can lose information (double to int drops the fraction). That is a feature: int cents = price * 100; would compile silently and truncate 998.999… to 998.

The fix

Decide how to convert and say so. For money, round rather than truncate, or better, store amounts as integer cents from the start.

C++
#include <cmath>

int main() {
    double price = 9.99;
    int cents{static_cast<int>(std::lround(price * 100))};
    return cents;
}
Error you will hit

8. variable type is an abstract class

C++
struct Shape {
    virtual double area() const = 0;
    virtual ~Shape() = default;
};

int main() {
    Shape s;
    return 0;
}
main.cpp:7:11: error: variable type 'Shape' is an abstract class
    7 |     Shape s;
      |           ^
main.cpp:2:20: note: unimplemented pure virtual method 'area' in 'Shape'
    2 |     virtual double area() const = 0;
      |                    ^
1 error generated.
Why the compiler said that

A class with a pure virtual function (= 0) is an interface: it cannot be created on its own. The same error appears for a derived class that forgot to override one of the pure virtual functions; the note says which one.

The fix

Create a concrete derived class that implements every pure virtual function, and use the base only through references or pointers (Module 08).

C++
struct Shape {
    virtual double area() const = 0;
    virtual ~Shape() = default;
};

struct Square : Shape {
    double side = 2;
    double area() const override { return side * side; }
};

int main() {
    Square s;
    const Shape& shape = s;
    return static_cast<int>(shape.area());
}
Error you will hit

9. call to implicitly-deleted copy constructor of unique_ptr

C++
#include <memory>
#include <vector>

int main() {
    auto p = std::make_unique<int>(42);
    std::unique_ptr<int> copy = p;
    return *copy;
}
main.cpp:6:26: error: call to implicitly-deleted copy constructor of 'std::unique_ptr<int>'
    6 |     std::unique_ptr<int> copy = p;
      |                          ^      ~
.../c++/v1/__memory/unique_ptr.h:209:55: note: copy constructor is implicitly deleted because 'unique_ptr<int>' has a user-declared move constructor
  209 |   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 unique_ptr(unique_ptr&& __u) _NOEXCEPT
      |                                                       ^
1 error generated.
Why the compiler said that

A unique_ptr is the only owner of its object, so it cannot be copied; two owners would both delete it. The same error appears when you push a unique_ptr into a vector by copy, or pass it by value without moving.

The fix

Transfer ownership with std::move (the source becomes empty), pass it by reference if the callee only uses it, or switch to std::shared_ptr if shared ownership is genuinely needed.

C++
#include <memory>
#include <vector>

int main() {
    auto p = std::make_unique<int>(42);
    std::unique_ptr<int> owner = std::move(p);  // p is now empty
    return *owner;
}
05

Runtime exceptions: uncaught and caught

The standard library reports some errors by throwing exceptions derived from std::exception. An exception nobody catches calls std::terminate, which prints the exception type and its what() message and aborts the program (exit code 134, SIGABRT).

Error you will hit

11. std::out_of_range from vector::at

C++
#include <iostream>
#include <vector>

int main() {
    std::vector<int> scores{90, 85, 77};
    std::cout << scores.at(3) << '\n';
}
libc++abi: terminating due to uncaught exception of type std::out_of_range: vector
Why the compiler said that

The vector has indexes 0 to 2. at() checks the index and throws. The same mistake with scores[3] is not checked: it is undefined behaviour that may print garbage or crash.

The fix

Loop with range-for or up to size(), check the index before using it, or catch the exception where you can respond sensibly.

C++
#include <iostream>
#include <vector>

int main() {
    std::vector<int> scores{90, 85, 77};
    std::size_t i = 3;
    if (i < scores.size()) std::cout << scores.at(i) << '\n';
    else std::cout << "no score at index " << i << '\n';
}
Error you will hit

12. std::invalid_argument from std::stoi

C++
#include <iostream>
#include <string>

int main() {
    std::string qty = "two";
    std::cout << std::stoi(qty) << '\n';
}
libc++abi: terminating due to uncaught exception of type std::invalid_argument: stoi: no conversion
Why the compiler said that

std::stoi throws std::invalid_argument when the text does not start with a number, and std::out_of_range when the number does not fit in an int. User input and file data hit this constantly.

The fix

Catch both exceptions around the conversion, or use std::from_chars, which reports errors through a return code instead of throwing.

C++
#include <charconv>
#include <iostream>
#include <string>

int main() {
    std::string qty = "two";
    int value = 0;
    auto [ptr, ec] = std::from_chars(qty.data(), qty.data() + qty.size(), value);
    if (ec == std::errc{}) std::cout << value << '\n';
    else std::cout << "not a number: " << qty << '\n';
}

Catching by const reference to the most specific type you can handle, with std::exception as the last resort, lets the program report the problem and carry on:

C++main.cpp
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

int parseQty(const std::string& s) {
    try {
        return std::stoi(s);
    } catch (const std::invalid_argument&) {
        throw std::runtime_error("bad quantity '" + s + "'");
    }
}

int main() {
    std::vector<std::string> inputs{"3", "two", "99999999999"};
    for (const auto& in : inputs) {
        try {
            int qty = parseQty(in);          // may throw: nothing printed yet
            std::cout << "qty " << qty << '\n';
        } catch (const std::out_of_range& e) {
            std::cout << "too big: " << e.what() << '\n';
        } catch (const std::exception& e) {
            std::cout << "error: " << e.what() << '\n';
        }
    }

    std::vector<int> v{1, 2, 3};
    try {
        v.at(10) = 5;
    } catch (const std::out_of_range& e) {
        std::cout << "out_of_range: " << e.what() << '\n';
    }
}
Outputcompiled & run with real C++
qty 3
error: bad quantity 'two'
too big: stoi: out of range
out_of_range: vector

parseQty translates a low-level exception into one with context (which input was bad), a habit that makes production logs readable. The what() texts come from libc++; libstdc++ on Linux words them differently.

06

Memory errors and AddressSanitizer

The worst C++ bugs produce no error at all: reading through a null, dangling or out-of-bounds pointer is undefined behaviour, and the program may crash, print garbage, or seem fine. AddressSanitizer (-fsanitize=address, in clang and gcc, and MSVC as /fsanitize=address) instruments every memory access and stops at the first bad one with a report naming the line. Add -g so reports show file and line numbers. Use it on every debug build and test run.

Error you will hit

13. Segmentation fault: dereferencing a null pointer

C++
#include <iostream>

struct Node { int value; Node* next; };

int main() {
    Node* head = nullptr;
    std::cout << head->value << '\n';
}
$ ./prog                       # plain build: the program just dies, exit code 139
$ c++ -std=c++20 -g -fsanitize=address main.cpp -o prog && ./prog
AddressSanitizer:DEADLYSIGNAL
=================================================================
==91030==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x0001023986d8 bp 0x00016da66630 sp 0x00016da66610 T0)
==91030==The signal is caused by a READ memory access.
==91030==Hint: address points to the zero page.
    #0 0x0001023986d8 in main main.cpp:7
    #1 0x0001870084e0 in start+0x1b4c (dyld:arm64e+0x204e0)
...
SUMMARY: AddressSanitizer: SEGV main.cpp:7 in main
==91030==ABORTING
Why the compiler said that

Reading head->value reads memory at address 0, which the OS never maps, so the process receives SIGSEGV. Without the sanitizer you get no message at all, only exit code 139 (the shell may print "segmentation fault"). The sanitizer's stack (#0 … main.cpp:7) names the line.

The fix

Check pointers that can be null before using them, and prefer references (which cannot be null) or std::optional in interfaces.

C++
#include <iostream>

struct Node { int value; Node* next; };

int main() {
    Node* head = nullptr;
    if (head) std::cout << head->value << '\n';
    else std::cout << "empty list\n";
}
Error you will hit

14. heap-use-after-free

C++
#include <iostream>

int main() {
    int* balance = new int(500);
    delete balance;
    std::cout << *balance << '\n';
}
$ ./prog                       # plain build: prints garbage and exits 0
4
$ c++ -std=c++20 -g -fsanitize=address main.cpp -o prog && ./prog
=================================================================
==91124==ERROR: AddressSanitizer: heap-use-after-free on address 0x6020000000f0 at pc 0x000104ab475c bp 0x00016b34a5c0 sp 0x00016b34a5b8
READ of size 4 at 0x6020000000f0 thread T0
    #0 0x000104ab4758 in main main.cpp:6

freed by thread T0 here:
    #0 0x000105398558 in _ZdlPv+0x74 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x50558)
    #1 0x000104ab4704 in main main.cpp:5

previously allocated by thread T0 here:
    #0 0x000105398150 in _Znwm+0x74 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x50150)
    #1 0x000104ab468c in main main.cpp:4

SUMMARY: AddressSanitizer: heap-use-after-free main.cpp:6 in main
Why the compiler said that

After delete, the memory belongs to the allocator again; reading it is undefined behaviour. The plain build printed 4, not 500, and exited successfully, which is exactly why these bugs survive into production. ASan reports all three places: the bad read (line 6), the free (line 5) and the allocation (line 4).

The fix

Do not manage memory with raw new/delete. Use a plain value, or std::unique_ptr, whose object lives exactly as long as its owner (Module 06).

C++
#include <iostream>
#include <memory>

int main() {
    auto balance = std::make_unique<int>(500);
    std::cout << *balance << '\n';
}   // freed automatically here, after the last use
Error you will hit

15. Dangling reference after vector::push_back

C++
#include <iostream>
#include <vector>

int main() {
    std::vector<int> v{1, 2, 3};
    int& first = v[0];
    v.push_back(4);
    std::cout << first << '\n';
}
$ ./prog                       # plain build: prints garbage (should be 1)
4
$ c++ -std=c++20 -g -fsanitize=address main.cpp -o prog && ./prog
=================================================================
==91178==ERROR: AddressSanitizer: heap-use-after-free on address 0x6020000000f0 at pc 0x000100cf4b20 bp 0x00016f10a450 sp 0x00016f10a448
READ of size 4 at 0x6020000000f0 thread T0
    #0 0x000100cf4b1c in main main.cpp:8

0x6020000000f0 is located 0 bytes inside of 12-byte region [0x6020000000f0,0x6020000000fc)
freed by thread T0 here:
    #0 0x0001016b0558 in _ZdlPv+0x74 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x50558)
    ...
    #10 0x000100cf4dd8 in std::__1::vector<int, std::__1::allocator<int>>::push_back[abi:nqe220106](int&&) vector.h:466
    #11 0x000100cf4ab8 in main main.cpp:7
Why the compiler said that

The vector was full, so push_back allocated a bigger buffer, moved the elements and freed the old 12-byte buffer. first still refers into the freed buffer. The same applies to pointers and iterators into a vector: any operation that can reallocate invalidates them.

The fix

Take the reference after the last insertion, keep an index instead of a reference, or reserve() enough capacity up front if you must keep references stable.

C++
#include <iostream>
#include <vector>

int main() {
    std::vector<int> v{1, 2, 3};
    std::size_t firstIndex = 0;
    v.push_back(4);
    std::cout << v[firstIndex] << '\n';
}
07

Debugging tools: warnings, sanitizers, a debugger

ToolFindsHow
Compiler warningsUninitialised variables, sign comparisons, unused results, missing returns-Wall -Wextra -Wpedantic, and -Werror in CI
AddressSanitizerOut-of-bounds, use-after-free, double free, leaks (on Linux)-fsanitize=address -g
UndefinedBehaviorSanitizerSigned overflow, bad shifts, misaligned or null access, invalid enum values-fsanitize=undefined
ThreadSanitizerData races between threads-fsanitize=thread (not together with ASan)
Debugger (lldb, gdb, Visual Studio)Anything: step line by line and inspect stateBuild with -g -O0, set breakpoints
Static analysisBugs and style issues without running the codeclang-tidy, cppcheck, IDE inspections
Valgrind (Linux)Memory errors and leaks in an unmodified binaryvalgrind ./prog
bash
$ c++ -std=c++20 -g -O0 main.cpp -o prog
$ lldb ./prog
(lldb) breakpoint set --file main.cpp --line 12   # or: b main.cpp:12
(lldb) run                                      # runs until the breakpoint
(lldb) frame variable                           # show every local variable
(lldb) print total                              # show one expression
(lldb) next                                     # run the current line, step over calls
(lldb) step                                     # step into the call on this line
(lldb) bt                                       # backtrace: who called whom
(lldb) continue
(lldb) quit

A minimal lldb session (gdb uses almost the same commands: run, break, next, step, print, bt).

For quick investigations, print to std::cerr (unbuffered, and kept separate from real output), and check assumptions with assert, which aborts with the file and line when a condition is false in debug builds and disappears when compiled with -DNDEBUG.

C++main.cpp
#include <cassert>
#include <iostream>
#include <vector>

double average(const std::vector<int>& xs) {
    assert(!xs.empty() && "average of an empty vector");
    long long sum = 0;
    for (int x : xs) sum += x;
    std::cerr << "[debug] sum=" << sum << " n=" << xs.size() << '\n';  // diagnostics to stderr
    return static_cast<double>(sum) / xs.size();
}

int main() {
    std::cout << average({3, 4, 8}) << '\n';
}
Outputcompiled & run with real C++
5

Only stdout (5) is the program's real output; the [debug] line goes to stderr, so redirecting output to a file or a pipe keeps it clean. Call average({}) in a debug build and the assert stops the program with the message and line number.

08

Index of the 15 errors

#Message (clang)StageUsual fix
1expected ';' at end of declarationCompileAdd the semicolon at the caret
2use of undeclared identifier 'cout'Compilestd:: prefix, or the missing #include
3no matching function for call to …CompileRead the notes: which argument, which types
4cannot assign to variable … with const-qualified typeCompileDrop const, or do not assign
5no member named … in …CompileTypo, or wrong type; check the class
6invalid operands to binary expressionCompileDefine the operator (e.g. operator<<)
7cannot be narrowed … in initializer listCompileExplicit conversion, round deliberately
8variable type … is an abstract classCompileInstantiate a concrete derived class
9call to implicitly-deleted copy constructor of 'std::unique_ptr'Compilestd::move, or pass by reference
10Undefined symbols / undefined reference toLinkDefine it, add the source file or library
11uncaught exception of type std::out_of_rangeRunCheck bounds; catch where you can recover
12uncaught exception of type std::invalid_argument: stoiRunValidate input; std::from_chars
13SEGV on unknown address 0x000000000000Run (UB)Check for null; prefer references
14heap-use-after-freeRun (UB)Smart pointers instead of new/delete
15heap-use-after-free after push_backRun (UB)Do not hold references across reallocation
Diagnostic
A compiler message: file:line:column, severity (error, warning, note), message, and a caret under the problem.
Linker
The tool that joins object files and libraries into a program and resolves every function call to exactly one definition.
Undefined behaviour (UB)
Code the language gives no meaning to (null or dangling access, out-of-bounds reads, signed overflow); anything may happen.
std::terminate
Called when an exception is not caught; prints the exception and aborts the program.
AddressSanitizer
A compiler instrumentation (-fsanitize=address) that detects invalid memory accesses at the moment they happen.
Backtrace
The chain of function calls that led to the current point, shown by a debugger (bt) or a sanitizer report.
Quick check

A program compiles, but building it fails with Undefined symbols for architecture arm64: "tax(double)". What is wrong?

Quick check

A program that reads a deleted pointer prints a plausible number and exits with code 0. What is the best way to find the bug?

Frequently asked questions

What is the difference between a compile error and a linker error in C++?
A compile error means one source file is not valid C++: a syntax mistake, a type mismatch or an unknown name, reported with a file, line and column. A linker error happens after every file compiled: a declared function or variable has no definition in any object file or library, so the linker reports an undefined symbol without a line number.
How do I debug a segmentation fault in C++?
Rebuild with -g -fsanitize=address and run the program again: AddressSanitizer reports the invalid access and the line that caused it. Alternatively run it under a debugger (lldb or gdb) and type bt after the crash to see the backtrace. Common causes are null pointers, dangling pointers or references, and out-of-bounds indexes.
Why does my C++ program work on my machine but crash elsewhere?
Usually undefined behaviour: reading uninitialised memory, a dangling reference, an out-of-bounds index or signed overflow. It can appear to work by chance with one compiler, optimisation level or memory layout and fail with another. Warnings (-Wall -Wextra) and sanitizers find most of these bugs.

Finish the C++ handbook, then get hired

Sit the exam for your certificate, run your resume through the ATS checker, and see the jobs that ask for exactly this.

Check my resume
Found this course useful? Share it.
ShareXLinkedIn

Comments

0

Join the conversation. Sign in to leave a comment — we'd love to hear your thoughts.