C++程序运行时内存分为四个核心区域:代码区、全局区、栈区和堆区。代码区存放函数体的二进制代码,由操作系统管理;全局区存储全局变量、静态变量和常量;栈区由编译器自动分配释放,存放函数参数值和局部变量;堆区由程序员手动分配释放,若不及时释放可能造成内存泄漏。
栈区内存分配效率极高但空间有限(通常1-2MB),适合存放生命周期明确的临时数据。例如函数内定义的int型变量默认分配在栈上:
cpp复制void func() {
int a = 10; // 栈区分配
}
堆区内存空间更大但需要手动管理,通过new/delete操作符进行分配释放:
cpp复制int* p = new int(20); // 堆区分配
delete p; // 必须显式释放
new操作符在堆区分配内存时实际完成三个步骤:1)调用operator new分配原始内存 2)调用构造函数初始化对象 3)返回对象指针。对应的delete操作符则执行:1)调用析构函数 2)调用operator delete释放内存。
对于数组类型需使用new[]/delete[]形式:
cpp复制int* arr = new int[10]; // 分配10个int的数组
delete[] arr; // 释放数组内存
常见错误包括:
关键提示:建议将new/delete操作封装在RAII对象中,利用构造函数分配资源、析构函数释放资源,可有效避免内存泄漏。
现代C++提供了三种智能指针模板类:
cpp复制std::unique_ptr<int> p1(new int(5));
auto p2 = std::move(p1); // 所有权转移
cpp复制std::shared_ptr<int> p3 = std::make_shared<int>(10);
auto p4 = p3; // 引用计数+1
智能指针的最佳实践:
函数模板通过参数化类型实现代码复用,编译时会根据调用参数类型实例化具体函数。典型声明形式:
cpp复制template<typename T>
T max(T a, T b) {
return a > b ? a : b;
}
编译器处理模板时经历两个阶段:
类型推导规则:
类模板允许数据类型参数化,典型声明形式:
cpp复制template<typename T>
class Vector {
private:
T* elements;
size_t size;
public:
explicit Vector(size_t n) : size(n) {
elements = new T[n];
}
~Vector() { delete[] elements; }
};
模板特化包括:
cpp复制template<>
class Vector<bool> { /* 位向量特化实现 */ };
cpp复制template<typename T>
class Vector<T*> { /* 指针类型的特殊处理 */ };
模板元编程(TMP)利用模板在编译期进行计算,典型应用包括:
cpp复制template<int N>
struct Factorial {
static const int value = N * Factorial<N-1>::value;
};
template<>
struct Factorial<0> { static const int value = 1; };
cpp复制template<typename T>
struct is_pointer { static const bool value = false; };
template<typename T>
struct is_pointer<T*> { static const bool value = true; };
现代C++中可用constexpr函数替代部分TMP场景,但模板元编程在类型操作方面仍有不可替代的优势。
通过模板实现自定义STL分配器:
cpp复制template<typename T>
class MyAllocator {
public:
using value_type = T;
T* allocate(size_t n) {
void* p = malloc(n * sizeof(T));
if (!p) throw std::bad_alloc();
return static_cast<T*>(p);
}
void deallocate(T* p, size_t) noexcept {
free(p);
}
};
应用示例:
cpp复制std::vector<int, MyAllocator<int>> v;
结合模板与RAII实现通用资源管理:
cpp复制template<typename T, typename Deleter = std::default_delete<T>>
class ScopedResource {
T* resource;
Deleter deleter;
public:
explicit ScopedResource(T* r) : resource(r) {}
~ScopedResource() { deleter(resource); }
// 禁用拷贝
ScopedResource(const ScopedResource&) = delete;
ScopedResource& operator=(const ScopedResource&) = delete;
// 允许移动
ScopedResource(ScopedResource&& other) noexcept
: resource(other.resource) { other.resource = nullptr; }
};
valgrind --leak-check=full ./program性能实测数据:在100万次int分配测试中,make_shared相比直接new+shared_ptr构造快约15%,内存占用减少20%。对于小型对象(<=32字节),自定义内存池可提升分配速度3-5倍。