C++ - Troubleshooting & Common Errors
A reference guide for diagnosing and fixing common C++ compiler errors, linker failures, and runtime memory crashes.
1. Linker Error: undefined reference to '...' (or LNK2019)
Occurs during the linking stage when a function or symbol is declared in a header file (.h), but its implementation cannot be located by the linker.
Common Causes & Solutions
- Missing Implementation File in Build: The
.cppcontaining the function was omitted from yourCMakeLists.txtor compiler command line:# Wrong: forgot to link math.cpp g++ main.cpp -o app # Fix: g++ main.cpp math.cpp -o app - Signature Mismatch: The parameter types or const-qualification in
.hand.cppdiffer:// header.h void process(const std::string& s); // source.cpp - MISMATCH (missing const) void process(std::string& s) { ... } - Template Definitions in
.cpp: Templates must be defined in header files so the compiler can instantiate them in each translation unit where they are called. - C vs C++ Linkage (
extern "C"): When calling C functions from C++, declare them insideextern "C"to prevent C++ name mangling:extern "C" { #include "legacy_c_lib.h" }
2. Compiler Warning: class has virtual functions but non-virtual destructor
The Problem
If a base class contains virtual functions, it is intended to be used polymorphically. If you delete a derived class object through a pointer to the base class:
Base* obj = new Derived();
delete obj; // Undefined Behavior if ~Base() is not virtual!
Without a virtual destructor, only ~Base() executes; ~Derived() is skipped, leaking any resources (memory, file handles, locks) owned by the derived class.
The Fix
Always mark the base class destructor virtual:
class Base {
public:
virtual ~Base() = default;
};
3. candidate function not viable: expects an rvalue for 1st argument
The Problem
You are trying to pass an lvalue (named variable) into a function expecting an rvalue reference (T&&):
void consume(std::string&& data);
std::string text = "hello";
consume(text); // ERROR: expects rvalue reference
The Fix
Explicitly cast the variable to an rvalue using std::move:
consume(std::move(text)); // OK: ownership transferred to consume
Caution: Once an object is moved via
std::move(), it enters a valid but unspecified state. Do not read or dereference it afterwards.
4. Runtime Error: heap-use-after-free / Segmentation Fault
Common Causes
- Use After Move: Accessing an object (especially smart pointers like
std::unique_ptr) after transferring ownership:auto ptr = std::make_unique<Widget>(); process(std::move(ptr)); ptr->doSomething(); // CRASH: ptr is now nullptr! - Dangling References / Pointers: Returning a reference to a local stack variable from a function:
// FATAL BUG: returns reference to stack memory that is destroyed on return const std::string& getTemp() { std::string s = "temporary"; return s; } - Iterator Invalidation: Modifying a container (like
std::vector::push_backtriggering a reallocation) while iterating through it.
5. Debugging with AddressSanitizer (ASan)
Instead of debugging segmentation faults blind, compile with LLVM/GCC AddressSanitizer to pinpoint the exact source file and line number of memory errors:
g++ -fsanitize=address,undefined -g -O1 main.cpp -o main
./main
ASan immediately intercepts memory violations and prints a stack trace:
=================================================================
==12345==ERROR: AddressSanitizer: heap-use-after-free on address 0x603000000040
READ of size 8 at 0x603000000040 thread T0
#0 0x401234 in main main.cpp:24
#1 0x7f9912 in __libc_start_main