内存管理

内存布局

理解 C++ 如何管理内存对于编写高效程序至关重要。内存分为不同的段:

局部变量、函数参数、返回地址

动态分配的内存(new/delete)

数据段

全局变量和静态变量

代码段

编译后的程序指令

内存分配示例

#include <iostream>
using namespace std;

int globalVar = 100;        // Data segment
static int staticVar = 200; // Data segment

void demonstrateMemory() {
    int localVar = 300;     // Stack
    static int staticLocal = 400; // Data segment
    
    int* heapVar = new int(500); // Heap
    
    cout << "Global variable address: " << &globalVar << endl;
    cout << "Static variable address: " << &staticVar << endl;
    cout << "Local variable address: " << &localVar << endl;
    cout << "Static local address: " << &staticLocal << endl;
    cout << "Heap variable address: " << heapVar << endl;
    
    delete heapVar; // Clean up heap memory
}

int main() {
    demonstrateMemory();
    return 0;
}

智能指针 (C++11)

智能指针自动管理内存,有助于防止内存泄漏:

智能指针示例

#include <iostream>
#include <memory>
using namespace std;

class Resource {
public:
    Resource(int id) : id(id) {
        cout << "Resource " << id << " created" << endl;
    }
    
    ~Resource() {
        cout << "Resource " << id << " destroyed" << endl;
    }
    
    void use() {
        cout << "Using resource " << id << endl;
    }

private:
    int id;
};

int main() {
    cout << "=== unique_ptr ===" << endl;
    {
        unique_ptr<Resource> ptr1 = make_unique<Resource>(1);
        ptr1->use();
        
        // Transfer ownership
        unique_ptr<Resource> ptr2 = move(ptr1);
        if (!ptr1) {
            cout << "ptr1 is now null" << endl;
        }
        ptr2->use();
    } // ptr2 automatically deletes the resource
    
    cout << "\n=== shared_ptr ===" << endl;
    {
        shared_ptr<Resource> ptr1 = make_shared<Resource>(2);
        cout << "Reference count: " << ptr1.use_count() << endl;
        
        {
            shared_ptr<Resource> ptr2 = ptr1; // Share ownership
            cout << "Reference count: " << ptr1.use_count() << endl;
            ptr2->use();
        } // ptr2 goes out of scope
        
        cout << "Reference count: " << ptr1.use_count() << endl;
        ptr1->use();
    } // ptr1 goes out of scope, resource is deleted
    
    cout << "\n=== weak_ptr ===" << endl;
    {
        shared_ptr<Resource> shared = make_shared<Resource>(3);
        weak_ptr<Resource> weak = shared;
        
        cout << "Weak pointer expired: " << weak.expired() << endl;
        
        if (auto locked = weak.lock()) {
            locked->use();
        }
        
        shared.reset(); // Release shared ownership
        cout << "Weak pointer expired: " << weak.expired() << endl;
    }
    
    return 0;
}

RAII 原则

资源获取即初始化 - 在构造函数中获取资源,在析构函数中释放资源:

RAII 示例

#include <iostream>
#include <fstream>
#include <vector>
using namespace std;

class FileManager {
private:
    ofstream file;

public:
    FileManager(const string& filename) : file(filename) {
        if (!file.is_open()) {
            throw runtime_error("Could not open file");
        }
        cout << "File opened: " << filename << endl;
    }
    
    ~FileManager() {
        if (file.is_open()) {
            file.close();
            cout << "File closed automatically" << endl;
        }
    }
    
    void write(const string& data) {
        file << data << endl;
    }
};

class ArrayManager {
private:
    int* data;
    size_t size;

public:
    ArrayManager(size_t s) : size(s) {
        data = new int[size];
        cout << "Array of size " << size << " allocated" << endl;
    }
    
    ~ArrayManager() {
        delete[] data;
        cout << "Array deallocated" << endl;
    }
    
    // Copy constructor (Rule of Three)
    ArrayManager(const ArrayManager& other) : size(other.size) {
        data = new int[size];
        for (size_t i = 0; i < size; ++i) {
            data[i] = other.data[i];
        }
    }
    
    // Assignment operator
    ArrayManager& operator=(const ArrayManager& other) {
        if (this != &other) {
            delete[] data;
            size = other.size;
            data = new int[size];
            for (size_t i = 0; i < size; ++i) {
                data[i] = other.data[i];
            }
        }
        return *this;
    }
    
    int& operator[](size_t index) {
        return data[index];
    }
};

int main() {
    cout << "=== RAII with File ===" << endl;
    try {
        FileManager fm("example.txt");
        fm.write("Hello, RAII!");
        fm.write("Automatic cleanup!");
        // File automatically closed when fm goes out of scope
    } catch (const exception& e) {
        cout << "Error: " << e.what() << endl;
    }
    
    cout << "\n=== RAII with Array ===" << endl;
    {
        ArrayManager arr(5);
        for (int i = 0; i < 5; ++i) {
            arr[i] = i * 10;
        }
        
        ArrayManager arr2 = arr; // Copy constructor
        // Both arrays automatically cleaned up
    }
    
    return 0;
}

内存管理最佳实践

优先使用栈分配

尽可能使用自动存储期

使用智能指针

对于动态分配,优先使用智能指针而不是原始指针

遵循 RAII

将资源生命周期与对象生命周期绑定

三/五法则

如果需要析构函数、复制构造函数或赋值运算符,通常都需要

初始化指针

始终将指针初始化为 nullptr 或有效地址

检查空指针

在解引用之前始终检查指针