What You'll Learn
- Assert and static_assert for invariants
- Common memory bugs and fixes
- Sanitizers (ASan, UBSan, TSan)
- GDB/Valgrind essential commands
Advanced Debugging
C++ gives you direct memory access — which means bugs can be subtle, dangerous, and hard to reproduce. This lesson covers the tools and techniques that professional C++ developers use daily: assertions, sanitizers, debuggers, and memory analysis tools.
Assertions & Debug Logging
assert() checks a condition at runtime and aborts with a message if it's false. static_assert checks at compile time — perfect for platform requirements. Both document your assumptions and catch bugs early.
Pro Tip: Assertions are disabled in release builds (-DNDEBUG). Never put side effects inside assert — assert(file.open()) silently skips the open in release!
Assertions & Logging
Use assert, static_assert, and debug macros
#include <iostream>
#include <cassert>
#include <string>
#include <vector>
using namespace std;
// Compile-time assertions (C++11)
static_assert(sizeof(int) >= 4, "int must be at least 4 bytes");
static_assert(sizeof(double) == 8, "double must be 8 bytes");
// Debug-only logging macro
#ifdef NDEBUG
#define DEBUG_LOG(msg)
#else
#define DEBUG_LOG(msg) cerr << "[DEBUG " << __FILE__ << ":" << __LINE__ << "] " << msg << endl
#endif
// Pre/post condition checking
double safeDivide(double a, dou
...Common Memory Bugs & Sanitizers
The four most common C++ memory bugs are: use-after-free, buffer overflow, uninitialized reads, and double free. Compiler sanitizers catch these automatically — just add -fsanitize=address to your build flags.
Common Mistake: Not using sanitizers during development. ASan has only 2× overhead — fast enough for CI and most testing. Enable it by default in debug builds.
Memory Bugs & Fixes
See common bugs and their safe alternatives
#include <iostream>
#include <vector>
#include <memory>
#include <cstring>
using namespace std;
// Common memory bugs and how to fix them
// Bug 1: Use-after-free
void useAfterFreeDemo() {
cout << "=== Use-After-Free ===" << endl;
// BAD (commented out — would crash with ASan):
// int* p = new int(42);
// delete p;
// cout << *p; // UB! ASan catches this
// GOOD: use smart pointers
auto p = make_unique<int>(42);
cout << "Value: " << *p << endl;
p.reset();
...GDB & Valgrind Essentials
GDB (GNU Debugger) lets you pause execution, inspect variables, and step through code line by line. Valgrind detects memory leaks and errors at runtime. Together, they're the standard C++ debugging toolkit on Linux and macOS.
Always compile with -g -O0 for debugging — -g includes debug symbols and -O0 disables optimizations that reorder code and remove variables.
GDB & Valgrind
Debug code with breakpoints and memory analysis
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// This program demonstrates code you'd debug with GDB/LLDB
struct Student {
string name;
vector<int> grades;
double average() const {
if (grades.empty()) return 0.0;
double sum = 0;
for (int g : grades) sum += g;
return sum / grades.size();
}
};
void processStudents(vector<Student>& students) {
// Set a breakpoint here: break processStudents
for (auto& s : stu
...Quick Reference
| Tool | Flag / Command | Detects |
|---|---|---|
| ASan | -fsanitize=address | Buffer overflow, use-after-free |
| UBSan | -fsanitize=undefined | Undefined behaviour |
| TSan | -fsanitize=thread | Data races |
| GDB | gdb ./program | Logic bugs, crashes |
| Valgrind | valgrind --leak-check=full | Memory leaks |
Lesson Complete!
You now have the debugging toolkit to find and fix memory errors, undefined behaviour, and logic bugs in C++ programs.
Sign up for free to track which lessons you've completed and get learning reminders.