C++ Memory Leaks: Causes, Detection, and Prevention with Smart Pointers
이 글의 핵심
Practical guide to C++ memory leaks: causes, tools, and RAII.
What is a memory leak?
Memory you allocated but never freed (or never release ownership of), so it stays allocated until process exit.
// ❌ Leak
void func() {
int* ptr = new int(10);
}
// ✅ Correct cleanup
void func() {
int* ptr = new int(10);
delete ptr;
}
Common causes
// 1. Missing delete
int* ptr = new int(10);
// 2. Exception skips delete
void func() {
int* ptr = new int(10);
throw std::runtime_error("error");
delete ptr;
}
// 3. Early return paths
int* func(bool flag) {
int* ptr = new int(10);
if (flag) {
return ptr;
}
delete ptr;
return nullptr;
}
// 4. shared_ptr cycles
class Node {
std::shared_ptr<Node> next;
std::shared_ptr<Node> prev;
};
Examples
Example 1: Basic leak vs smart pointer
#include <iostream>
class Widget {
public:
Widget(int size) : size(size) {
data = new int[size];
std::cout << "Widget alloc: " << size << std::endl;
}
~Widget() {
delete[] data;
std::cout << "Widget free: " << size << std::endl;
}
private:
int* data;
int size;
};
void leak() {
Widget* w = new Widget(100);
}
void noLeak() {
auto w = std::make_unique<Widget>(100);
}
int main() {
leak();
noLeak();
}
Example 2: Exception safety
#include <stdexcept>
void processData(bool throwError) {
int* data = new int[1000];
if (throwError) {
throw std::runtime_error("error");
}
delete[] data;
}
void processDataSafe(bool throwError) {
auto data = std::make_unique<int[]>(1000);
if (throwError) {
throw std::runtime_error("error");
}
}
int main() {
try {
processDataSafe(true);
} catch (const std::exception& e) {
std::cout << e.what() << std::endl;
}
}
Example 3: Containers of raw pointers
#include <vector>
class Resource {
public:
Resource() {
data = new int[100];
}
~Resource() {
delete[] data;
}
Resource(const Resource&) = delete;
Resource& operator=(const Resource&) = delete;
private:
int* data;
};
void leak() {
std::vector<Resource*> resources;
for (int i = 0; i < 10; i++) {
resources.push_back(new Resource());
}
}
void noLeak() {
std::vector<std::unique_ptr<Resource>> resources;
for (int i = 0; i < 10; i++) {
resources.push_back(std::make_unique<Resource>());
}
}
Example 4: Circular references
#include <memory>
class Node {
public:
std::shared_ptr<Node> next;
std::shared_ptr<Node> prev;
};
void circularReference() {
auto node1 = std::make_shared<Node>();
auto node2 = std::make_shared<Node>();
node1->next = node2;
node2->prev = node1;
}
class NodeFixed {
public:
std::shared_ptr<NodeFixed> next;
std::weak_ptr<NodeFixed> prev;
};
Detection
// Valgrind: valgrind --leak-check=full ./program
// ASan: g++ -fsanitize=address -g program.cpp
// MSVC debug: _CrtSetDbgFlag(...)
Common pitfalls
Pitfall 1: delete vs delete[]
int* arr = new int[10];
delete[] arr;
auto arr = std::make_unique<int[]>(10);
Pitfall 2: Double delete
delete ptr;
ptr = nullptr;
delete ptr; // safe no-op on nullptr
Pitfall 3: Unclear ownership
void func(std::unique_ptr<int> ptr) { }
std::unique_ptr<int> getData() {
return std::make_unique<int>(10);
}
Pitfall 4: vector::clear on raw pointers
for (auto ptr : vec) {
delete ptr;
}
vec.clear();
std::vector<std::unique_ptr<int>> vec;
vec.clear();
Prevention
auto ptr = std::make_unique<int>(10);
std::vector<int> vec(10);
FAQ
Q1: When do leaks happen?
A: Missing deletes, exceptions, cycles, unclear ownership.
Q2: How to detect?
A: Valgrind, AddressSanitizer, IDE leak tools.
Q3: How to prevent?
A: Smart pointers, RAII, avoid raw new in app code.
Q4: Performance impact?
A: Growing RSS, slower allocation, eventual instability.
Q5: Which smart pointer?
A: unique_ptr for sole ownership, shared_ptr + weak_ptr for shared graphs.
Q6: Resources?
A: Effective C++, C++ Core Guidelines, Valgrind docs.
See also
- C++ use-after-free
- C++ heap corruption
- C++ Valgrind
Practical tips
Debugging
- Enable warnings
- Minimize repro cases
Performance
- Profile hotspots
- Define metrics
Code review
- Follow conventions
Checklist
Before coding
- Right approach?
- Team can maintain?
- Performance OK?
While coding
- Warnings fixed?
- Edge cases?
- Errors handled?
At review
- Clear intent?
- Tests?
- Docs?
Keywords
C++, memory leak, memory, debugging, RAII, smart pointers.
Related posts
- C++ debugging techniques
- C++ heap corruption
- C++ sanitizers
- C++ use-after-free
- C++ Valgrind