C++内存管理——初阶
文章目录
C语言前章回顾
int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
static int staticVar = 1;
int localVar = 1;
int num1[10] = { 1, 2, 3, 4 };
char char2[] = "abcd";
const char* pChar3 = "abcd";
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)calloc(4, sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
free(ptr1);
free(ptr3);
}
- 选择题:
选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
globalVar在哪里?____C 已经赋值的全局变量/static修饰的变量位于静态区
staticGlobalVar在哪里?____C
staticVar在哪里?____ C
localVar在哪里?____A //其他main函数中的变量存在于栈
num1 在哪里?____A
char2在哪里?____ A
*char2在哪里?___A *char2 指向的是数组 数组存在于栈上
pChar3在哪里?____A
*pChar3在哪里?____D *pchar3指向的是 abcd常量 常量存在于 常量区
ptr1在哪里?____ A
*ptr1在哪里?___B

栈存放的是 函数内局部变量、函数参数、和返回值 例如:int a = 10;、char arr[5];
堆存放的是 动态分配的内存(需手动管理)
静态取存放的是 全局变量 静态变量
常量区 存放的是字符串常量 和 const修饰的常量
C++内存管理方式
C语言中的malloc……等函数在某些地方用起来比较麻烦,就比如类中我们需要调用构造调用析构。这时候malloc、relloc、calloc、free就显得很鸡肋。因此C++提出了 new和delete操作符进行动态内存管理
- new与delete特点
1.new和delete本身是一个操作符,可以通过指定的创建类型和要进行初始化的数值进行对象创建
2.new和delete在与类结合时会自动调用构造函数和析构函数
3.当new创建的是一个数组时,delete需要变成delete[] 操作符进行释放
不同类型创建方式
void Test()
{
//动态申请一个int类型的空间
int* ptr4 = new int;
//动态申请一个int类型的空间并且初始化为10
int* ptr5 = new int(10);
//动态申请10个int类型的空间
int* ptr6 = new int[10];
//动态申请10个int类型的空间并且初始化
int* ptr7 = new int[10] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
delete ptr4;
delete ptr5;
delete[] ptr6;
delete[] ptr7;
}

class A
{
public:
A(int a = 0)
:_a(a)
{
cout << "A():" << this << endl;
}
~A()
{
cout << "~A()" << this << endl;
}
private:
int _a;
};
int main()
{
//new/delete 和malloc/free最大的区别是new/delete对于 自定义类型除了开空间还会调用构造函数和析构函数
A* p1 = (A*)malloc(sizeof(A));
A* p2 = new A(1);
free(p1);
delete p2;
//内置类习惯几乎是一样的
int* p3 = (int*)malloc(sizeof(int));
int* p4 = new int;
free(p3);
delete p4;
A* p5 = (A*)malloc(sizeof(A) * 10);
A* p6 = new A[10];
free(p5);
delete[] p6;
return 0;
}
operator new 和 operator delete
- operator new 和new区别
operator new
1.本质:全局函数(可重载为类成员函数),仅负责分配原始内存(类似 C 语言的 malloc),不涉及对象构造。
2.功能:根据传入的 size_t 大小,在堆上分配对应字节的内存,失败时默认抛异常(可使用 nothrow 版本返回 nullptr)
void* raw_mem = operator new(sizeof(int)); // 分配4字节内存,返回void*
new
本质:C++ 关键字,用于创建对象,包含两个步骤:
① 调用 operator new 分配内存;
② 在分配的内存上自动调用对象的构造函数。
class A {
public:
A(int x) : _x(x) {} // 构造函数
private:
int _x;
};
A* p = new A(10); // 使用new关键字
// 等价于:
// 1. 分配内存:void* mem = operator new(sizeof(A));
// 2. 构造对象:A* p = new(mem) A(10); // placement new(显式调用构造函数)
- operator delete和delete的区别
operator delete
本质:全局函数(可重载为类成员函数),仅负责释放原始内存(类似 C 语言的 free),不涉及对象析构。
功能:接收 void* 指针,释放该指针指向的堆内存(需确保内存是 operator new 分配的)。
operator delete(raw_mem); // 释放之前分配的内存
delete
本质:C++ 关键字,用于销毁对象,包含两个步骤:
① 先调用对象的析构函数(清理对象资源);
② 调用 operator delete 释放内存。
delete p; // 使用delete关键字
// 等价于:
// 1. 析构对象:p->~A();
// 2. 释放内存:operator delete(p);

/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间
失败,尝试执行空
间不足应对措施,如果改应对措施用户设置了,则继续申请,否
*/
void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void* p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{
// report no memory
// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}
/*
operator delete: 该函数最终是通过free来释放空间的
*/
void operator delete(void* pUserData)
{
_CrtMemBlockHeader* pHead;
RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
if (pUserData == NULL)
return;
_mlock(_HEAP_LOCK); /* block other threads */
__TRY
/* get a pointer to memory block header */
pHead = pHdr(pUserData);
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg(pUserData, pHead->nBlockUse);
__FINALLY
_munlock(_HEAP_LOCK); /* release other threads */
__END_TRY_FINALLY
return;
}
总结——new和delete是精简版本,即使我们没有写显式的operator new函数和operator delete函数,但是当我们使用new创建对象和使用delete释放空间时,编译器也会自动调用operator new函数 和operator delete函数
new和delete实现原理
- 如果申请的是内置类型的空间,那么new和malloc、delete和free基本类似,不同的地方是 new/delete申请和释放的是单个元素空间。new[]\delete[]申请的是连续的空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。
- new的原理
1.调用operator new函数申请空间
2.在申请空间上执行构造函数,完成对象的构造
- delete的原理
1.在空间上执行析构函数,完成对象中资源的清理工作
2.调用operator delete函数释放对象空间
- new T[N]的原理
1.调用operator new[]函数,在operator new[] 中调用operator new 函数,完成N个对象空间的申请
2.调用构造函数N次,完成初始化
- delete T [N]的原理
1.调用析构函数N次,完成对资源的全部释放
2.调用operator delete N次,完成对空间的释放
定位new表达式(palacement-new)
定位new表达式 是已分配的原始内存空间中调用构造函数初始化一个对象
使用格式:
new(place_address)type,或者new(place_address) type (initializer-list) 注意place_address必须是一个指针,initializer-list 必须是初始化列表
定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。
int main()
{
//p1现在指向的是与A对象相同大小的一段空间,不能算是一个对象,因为构造函数没有执行
A* p1 = (A*)malloc(sizeof(A));
new(p1)A;
p1->~A();
free(p1);
A* p2 = (A*)operator new(sizeof(A));
new(p2)A(10);
p2->~A();
operator delete(p2);
return 0;
}
malloc/free和new/delete的区别
malloc/free 和new/delete共同特点就是都是在堆上申请空间,并且需要用户手动输入
1.malloc和free是函数,new和delete是操作符
2.malloc不会初始化,new会初始化
3.malloc申请空间失败返回NULL,new申请空间失败需要捕获异常
4.malloc申请空间需要手动出入大小,new不需要,只需要加上类型即可
5.malloc返回值是void* 需要强转,new不需要,因为new后面跟的就是空间类型
6.malloc/free智慧开辟空间,而new/delete会自动调用构造函数和析构函数
更多推荐

所有评论(0)