C++ 内存管理最佳实践详解
一、内存管理基础概念
1.1 内存区域划分
// C++程序内存布局
class MemoryLayout {
// 栈(Stack):存储局部变量、函数参数
void stackExample() {
int localVar = 10; // 栈上分配
char arr[100]; // 栈上分配
} // 函数结束,自动释放
// 堆(Heap):动态分配的内存
void heapExample() {
int* p = new int(10); // 堆上分配
delete p; // 手动释放
}
// 全局/静态存储区
static int staticVar; // 静态变量
// 常量存储区
const char* str = "Hello"; // 字符串常量
};
二、智能指针的使用
2.1 unique_ptr - 独占所有权
#include <memory>
#include <iostream>
class Resource {
int data;
public:
Resource(int d) : data(d) {
std::cout << "Resource " << data << " created\n";
}
~Resource() {
std::cout << "Resource " << data << " destroyed\n";
}
void use() { std::cout << "Using resource " << data << "\n"; }
};
// unique_ptr 最佳实践
class UniqueExample {
public:
// 1. 优先使用 make_unique(C++14)
void createResource() {
auto ptr = std::make_unique<Resource>(42);
ptr->use();
// 自定义删除器
auto customDeleter = [](Resource* p) {
std::cout << "Custom cleanup\n";
delete p;
};
std::unique_ptr<Resource, decltype(customDeleter)>
ptr2(new Resource(100), customDeleter);
}
// 2. 转移所有权
std::unique_ptr<Resource> transferOwnership() {
auto ptr = std::make_unique<Resource>(50);
return ptr; // 移动构造,不是拷贝
}
// 3. 管理数组
void manageArray() {
// C++14 方式
auto arr = std::make_unique<int[]>(10);
for(int i = 0; i < 10; ++i) {
arr[i] = i * i;
}
}
};
2.2 shared_ptr - 共享所有权
class SharedExample {
public:
// 1. 基本使用
void basicUsage() {
std::shared_ptr<Resource> ptr1 = std::make_shared<Resource>(1);
{
std::shared_ptr<Resource> ptr2 = ptr1; // 共享所有权
std::cout << "Reference count: " << ptr1.use_count() << "\n"; // 2
}
std::cout << "Reference count: " << ptr1.use_count() << "\n"; // 1
}
// 2. 避免循环引用
class Node {
int value;
public:
std::shared_ptr<Node> next;
std::weak_ptr<Node> parent; // 使用weak_ptr避免循环引用
Node(int val) : value(val) {}
};
// 3. enable_shared_from_this 模式
class Widget : public std::enable_shared_from_this<Widget> {
public:
std::shared_ptr<Widget> getShared() {
return shared_from_this(); // 安全获取this的shared_ptr
}
void process() {
// 错误做法:std::shared_ptr<Widget>(this);
// 正确做法:
auto self = shared_from_this();
// 使用self...
}
};
};
2.3 weak_ptr - 弱引用
class WeakExample {
// 观察者模式实现
class Subject;
class Observer {
std::weak_ptr<Subject> subject; // 不影响Subject的生命周期
public:
void setSubject(std::shared_ptr<Subject> s) {
subject = s;
}
void update() {
if(auto s = subject.lock()) { // 尝试获取shared_ptr
// 使用subject
std::cout << "Subject still alive\n";
} else {
std::cout << "Subject destroyed\n";
}
}
};
class Subject {
std::vector<std::shared_ptr<Observer>> observers;
public:
void attach(std::shared_ptr<Observer> obs) {
observers.push_back(obs);
}
};
};
三、RAII(资源获取即初始化)
3.1 RAII 原则实现
// 自定义RAII包装器
template<typename T>
class RAIIWrapper {
T* resource;
std::function<void(T*)> deleter;
public:
// 构造时获取资源
explicit RAIIWrapper(T* res, std::function<void(T*)> del = [](T* p){ delete p; })
: resource(res), deleter(del) {}
// 析构时释放资源
~RAIIWrapper() {
if(resource) {
deleter(resource);
}
}
// 禁用拷贝
RAIIWrapper(const RAIIWrapper&) = delete;
RAIIWrapper& operator=(const RAIIWrapper&) = delete;
// 允许移动
RAIIWrapper(RAIIWrapper&& other) noexcept
: resource(std::exchange(other.resource, nullptr))
, deleter(std::move(other.deleter)) {}
RAIIWrapper& operator=(RAIIWrapper&& other) noexcept {
if(this != &other) {
if(resource) deleter(resource);
resource = std::exchange(other.resource, nullptr);
deleter = std::move(other.deleter);
}
return *this;
}
T* get() { return resource; }
T* operator->() { return resource; }
T& operator*() { return *resource; }
};
// 文件句柄RAII
class FileHandle {
FILE* file;
public:
explicit FileHandle(const char* filename, const char* mode)
: file(fopen(filename, mode)) {
if(!file) throw std::runtime_error("Failed to open file");
}
~FileHandle() {
if(file) fclose(file);
}
FileHandle(FileHandle&& other) noexcept
: file(std::exchange(other.file, nullptr)) {}
// 禁用拷贝
FileHandle(const FileHandle&) = delete;
FileHandle& operator=(const FileHandle&) = delete;
FILE* get() { return file; }
};
四、内存池技术
4.1 简单内存池实现
template<typename T, size_t BlockSize = 4096>
class MemoryPool {
struct Block {
Block* next;
};
class Chunk {
char memory[BlockSize];
public:
Chunk* next;
};
Block* freeList = nullptr;
Chunk* chunks = nullptr;
size_t itemsPerChunk;
public:
MemoryPool() : itemsPerChunk(BlockSize / sizeof(T)) {
static_assert(sizeof(T) >= sizeof(Block*), "Type too small");
allocateChunk();
}
~MemoryPool() {
while(chunks) {
Chunk* next = chunks->next;
delete chunks;
chunks = next;
}
}
T* allocate() {
if(!freeList) {
allocateChunk();
}
Block* block = freeList;
freeList = freeList->next;
return reinterpret_cast<T*>(block);
}
void deallocate(T* ptr) {
if(!ptr) return;
Block* block = reinterpret_cast<Block*>(ptr);
block->next = freeList;
freeList = block;
}
private:
void allocateChunk() {
Chunk* newChunk = new Chunk;
newChunk->next = chunks;
chunks = newChunk;
char* start = newChunk->memory;
char* end = start + BlockSize;
for(char* p = start; p + sizeof(T) <= end; p += sizeof(T)) {
deallocate(reinterpret_cast<T*>(p));
}
}
};
// 使用内存池的分配器
template<typename T>
class PoolAllocator {
MemoryPool<T>& pool;
public:
using value_type = T;
explicit PoolAllocator(MemoryPool<T>& p) : pool(p) {}
T* allocate(size_t n) {
if(n != 1) throw std::bad_alloc();
return pool.allocate();
}
void deallocate(T* p, size_t n) {
if(n == 1) pool.deallocate(p);
}
};
五、避免内存泄漏
5.1 常见内存泄漏场景和解决方案
class MemoryLeakPrevention {
public:
// 1. 异常安全的资源管理
void exceptionSafe() {
// 错误做法
void badExample() {
Resource* r1 = new Resource(1);
Resource* r2 = new Resource(2); // 可能抛出异常
// 如果r2构造失败,r1泄漏
delete r2;
delete r1;
}
// 正确做法
void goodExample() {
auto r1 = std::make_unique<Resource>(1);
auto r2 = std::make_unique<Resource>(2);
// 异常安全,自动清理
}
}
// 2. 容器中的指针管理
class Container {
// 错误做法
std::vector<Resource*> badResources;
// 正确做法
std::vector<std::unique_ptr<Resource>> goodResources;
public:
void addResource(int value) {
goodResources.push_back(std::make_unique<Resource>(value));
}
};
// 3. 回调和lambda中的内存管理
class CallbackManager {
std::vector<std::function<void()>> callbacks;
public:
void registerCallback(std::shared_ptr<Resource> res) {
// 使用weak_ptr避免循环引用
std::weak_ptr<Resource> weakRes = res;
callbacks.push_back([weakRes]() {
if(auto r = weakRes.lock()) {
r->use();
}
});
}
};
};
六、性能优化技巧
6.1 减少内存分配
class PerformanceOptimization {
public:
// 1. 使用reserve预分配容器空间
void optimizeVector() {
std::vector<int> vec;
vec.reserve(1000); // 预分配空间,避免多次重新分配
for(int i = 0; i < 1000; ++i) {
vec.push_back(i);
}
}
// 2. 小对象优化(Small Object Optimization)
class OptimizedString {
static constexpr size_t SSO_SIZE = 15;
union {
char sso[SSO_SIZE + 1]; // 小字符串直接存储
char* ptr; // 大字符串使用堆
};
size_t size;
bool isSSO;
public:
OptimizedString(const char* str) {
size = strlen(str);
isSSO = size <= SSO_SIZE;
if(isSSO) {
strcpy(sso, str);
} else {
ptr = new char[size + 1];
strcpy(ptr, str);
}
}
~OptimizedString() {
if(!isSSO) {
delete[] ptr;
}
}
};
// 3. 移动语义优化
class MoveOptimized {
std::vector<int> data;
public:
// 移动构造函数
MoveOptimized(MoveOptimized&& other) noexcept
: data(std::move(other.data)) {}
// 移动赋值运算符
MoveOptimized& operator=(MoveOptimized&& other) noexcept {
if(this != &other) {
data = std::move(other.data);
}
return *this;
}
// 完美转发
template<typename T>
void processData(T&& value) {
data.push_back(std::forward<T>(value));
}
};
};
七、调试和工具
7.1 内存调试技巧
// 自定义内存跟踪
class MemoryTracker {
struct AllocationInfo {
size_t size;
std::string file;
int line;
};
static std::unordered_map<void*, AllocationInfo> allocations;
static std::mutex allocationMutex;
public:
static void* allocate(size_t size, const char* file, int line) {
void* ptr = malloc(size);
std::lock_guard<std::mutex> lock(allocationMutex);
allocations[ptr] = {size, file, line};
return ptr;
}
static void deallocate(void* ptr) {
std::lock_guard<std::mutex> lock(allocationMutex);
auto it = allocations.find(ptr);
if(it != allocations.end()) {
allocations.erase(it);
free(ptr);
} else {
std::cerr << "Attempting to free untracked memory!\n";
}
}
static void reportLeaks() {
std::lock_guard<std::mutex> lock(allocationMutex);
if(!allocations.empty()) {
std::cout << "Memory leaks detected:\n";
for(const auto& [ptr, info] : allocations) {
std::cout << " " << info.size << " bytes at "
<< info.file << ":" << info.line << "\n";
}
}
}
};
// 宏定义用于跟踪
#ifdef DEBUG_MEMORY
#define NEW(size) MemoryTracker::allocate(size, __FILE__, __LINE__)
#define DELETE(ptr) MemoryTracker::deallocate(ptr)
#else
#define NEW(size) malloc(size)
#define DELETE(ptr) free(ptr)
#endif
八、最佳实践总结
8.1 核心原则清单
class BestPractices {
public:
// 1. 优先使用智能指针而非裸指针
void rule1() {
// Bad
Resource* r = new Resource(1);
// ...
delete r;
// Good
auto r = std::make_unique<Resource>(1);
}
// 2. 使用make_unique和make_shared
void rule2() {
// Bad
std::shared_ptr<Resource> r(new Resource(1));
// Good
auto r = std::make_shared<Resource>(1);
}
// 3. 遵循RAII原则
class RAIIExample {
std::unique_ptr<Resource> resource;
public:
RAIIExample() : resource(std::make_unique<Resource>(1)) {}
// 自动管理生命周期
};
// 4. 避免循环引用
struct Node {
std::shared_ptr<Node> next;
std::weak_ptr<Node> prev; // 使用weak_ptr
};
// 5. 使用移动语义提高性能
std::vector<std::string> createStrings() {
std::vector<std::string> result;
result.reserve(100);
// ...
return result; // RVO/NRVO优化
}
};