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优化
    }
};