内存管理
内存布局
理解 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 或有效地址
检查空指针
在解引用之前始终检查指针