博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

C/CPP-内存管理

Posted on 2023-03-12 22:13  乔55  阅读(18)  评论(0编辑  收藏  举报

基本概念

// 存储分类
1. // 静态存储分配:对于我们定义的变量,通常,编译器在编译时都可以根据变量的类型知道所需要的内存空间的大小,系统从而在适当的时候为它们分配确定的存储空间
2. // 动态存储分配:有些操作对象只有在程序运行时才能确定,这样编译器在编译时就无法为它们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配。


// malloc与new
1. // malloc:只是申请空间,并不进行初始化
2. // new:申请空间,若为对象申请空间,还会调用类的构造函数做简单初始化
3. // free:若对象中有指针成员,则需要先将该指针指向空间销毁,再释放该对象
4. // delete:先调用析构函数将对象析构,再释放对象所占的内存空间。直接用delete完成
5. // new:new一个对象数组时:T* ptr = new T[10];必须有无参构造函数(或默认)


// 分配与释放基本概念
- 下标表达式不是常量表达式,即它的值不必在编译时确定,可以在运行时确定

// 常见内存错误
- // 使用未分配成功的内存:使用前应检查指针是否为NULL
- // 引用分配成功但没尚未初始化的内存:最好是对内存进行赋初值
- // 内存分配成功且初始化成功,但操作越界:注意下标的使用不能越界
- // 忘记释放内存,造成内存泄露:动态内存的申请与释放必须配对
- // 释放了内存却继续使用它:若没有置空,则会产生野指针,它指向垃圾内存

// 野指针
- // 指针变量没被初始化形成野指针,任何指针变量刚被创建时其缺省值是随机的,会乱指一气
- // 指针变量在创建是应当被初始化,要么将其置空,要么将其指向合法内存
- // 使用free释放内存后,将指针置空。若没有置空,就会产生野指针

malloc\calloc\realloc\free

// malloc函数
void* malloc(size_t n);
int* p = (int*)malloc(2*1024*1024*1024);      // 整型溢出
int* p = (int*)malloc(2u*1024u*1024u*1024u);  // 不会溢出
// 功能:从空间内存池中分配连续内存但不初始化
// 参数:size申请分配的字节数
// 返回:若分配成功,则返回一个指向该内存块的指针,若分配失败,则返回NULL
// 注意:malloc(0):正常分配,返回一个地址,但空间为0,无法使用


// calloc函数
void* calloc(size_t n, size_t size);
char* p = (char*)calloc(100,sizeof(char));  // 申请100个char空间
// 功能:功能同malloc,但是对所申请的内存空间初始化
// 初始化:calloc会新申请得到的内存自动初始化为0


// realloc函数
void* realloc(void* ptr, size_t new_size);
// 功能:将ptr指向的内存块扩大或缩小内存
// 特点1:当扩展内存时,不会对添加进内存块的字节初始化
// 特点2:若不能调整内存则返回NULL,且原有内存中数据不会发生变化 
// 特点3:若第1个参数为NULL,则等同于malloc,若第2个参数为0,则等同于free


// free函数
void free(void* ptr);
// 注意1:若ptr为NULL,则free对ptr操作多少次都不会出问题
// 注意2:若Ptr不是NULL,则free对ptr操作2次或以上,就会导致程序运行错误

new与delete

// new重载
void* operator new(size_t n)
{
  void* ptr = malloc(n);
  return ptr;
}

// delete重载
void operator delete(void* ptr)
{
  free(ptr);
}

// new所做的事情
- myString* ptr = new myString("hello");  // 将创建空间与初始化对象一步到位
  - myString* ptr = (myString*)operator new(sizeof(myString));  // 创建对象空间
  - new(ptr)myString("hello");  // 初始化对象

// delete所做的事
- delete ptr;                   // 释放,一步到位 
  - ptr->~myString();           // 调用myString类的析构函数销毁对象
  - operator delete(ptr);       // 释放对象空间

// new定位重载
void* operator new(size_t n, int* arr, int index)
{
  return &arr[index];
}
int arr[10];  // 定义10个元素的数组,静态
new(arr, 5)int(20);  // 在下标为5处将数据填入

造成内存泄露的情况

void* ptr = new Test[10];delete ptr;  // 泄露,无法知道ptr空间大小