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

  1. Missing Implementation File in Build: The .cpp containing the function was omitted from your CMakeLists.txt or compiler command line:
    # Wrong: forgot to link math.cpp
    g++ main.cpp -o app
    # Fix:
    g++ main.cpp math.cpp -o app
    
  2. Signature Mismatch: The parameter types or const-qualification in .h and .cpp differ:
    // header.h
    void process(const std::string& s);
    // source.cpp - MISMATCH (missing const)
    void process(std::string& s) { ... }
    
  3. 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.
  4. C vs C++ Linkage (extern "C"): When calling C functions from C++, declare them inside extern "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

  1. 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!
    
  2. 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;
    }
    
  3. Iterator Invalidation: Modifying a container (like std::vector::push_back triggering 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
Loading...