Introduction: Why C++ is Hard but Interesting
C++ is one of the most powerful and performant programming languages. But with great power comes great responsibility. Beginner developers often encounter errors that can lead to program crashes, memory leaks, and undefined behavior. In this article, we will break down the 10 most common mistakes beginners make in C++ — from A to Z. You will learn how to recognize them, fix them, and, most importantly, avoid them in the future. This material will be useful for both students and those just starting their journey in systems programming.
1. Ignoring Undefined Behavior (UB)
One of the most insidious mistakes is undefined behavior (UB). The compiler won't issue a warning, the program might seem to work "normally", but when optimizations or platforms change, everything will crash.
Example: Array Out-of-Bounds Access
int arr[5] = {1, 2, 3, 4, 5};arr[5] = 42; // UB: out-of-bounds writestd::cout << arr[10]; // UB: reading garbageHow to avoid: Always use std::array or std::vector with bounds checking via .at(), as well as STL containers. Never rely on "luck" — UB can manifest at the worst possible moment.
2. Memory Leaks and Raw Pointers
C++ has no garbage collector. Every new must have a matching delete. Beginners often forget to free memory, especially when exceptions occur.
Example of a Leak
void leak() { int* p = new int(100); // forgot delete p; // memory is lost when the function exits}Solution: Use smart pointers: std::unique_ptr for exclusive ownership and std::shared_ptr for shared ownership. They will automatically free memory when they go out of scope.
void no_leak() { auto p = std::make_unique<int>(100); // delete is called automatically}3. Incorrect Use of References and Pointers
Confusion between references (&) and pointers (*) is a common problem.
- Reference is an alias. It cannot be
nullptrand cannot be reassigned. - Pointer can be null and can point to different objects.
Typical Mistake: Returning a Reference to a Local Object
int& bad_ref() { int x = 10; return x; // x is destroyed after exit}// usage: int& r = bad_ref(); // dangling referenceRule: Never return references or pointers to local variables. Only return data whose lifetime is guaranteed (e.g., arguments passed by reference or static variables).
4. Neglecting RAII (Resource Acquisition Is Initialization)
RAII is a key C++ idiom. A resource (memory, file, mutex) is acquired in the constructor and released in the destructor. Beginners often write manual management, which leads to leaks when exceptions occur.
Bad Example
void handle_file() { FILE* f = fopen("data.txt", "r"); // ... work with file ... if (some_error) { return; // forgot fclose! } fclose(f);}Good Example with RAII
void handle_file_safe() { std::ifstream f("data.txt"); if (!f) return; // ... work ... // file is automatically closed when exiting scope}Conclusion: Always wrap resources in RAII wrappers. For files — std::fstream, for memory — smart pointers, for mutexes — std::lock_guard.
5. Ignoring const and constexpr
Many beginners do not use