我们先来看下面的一段代码和相关问题
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";//char2是首元素地址 a b c d \0
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);
}1. 选择题:
选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
globalVar在哪里?____C
staticGlobalVar在哪里?____C
staticVar在哪里?____C
localVar在哪里?____A
num1 在哪里?____A
char2在哪里?____A 首元素地址
*char2在哪里?___A *char就是a
pChar3在哪里?____A
*pChar3在哪里?____D 指向常量字符串
ptr1在哪里?____A
*ptr1在哪里?____B【说明】
void Test()
{
// malloc: 分配指定字节数的内存,不初始化
int* p1 = (int*)malloc(sizeof(int) * 4);
// calloc: 分配指定数量和大小的内存,并初始化为0
int* p2 = (int*)calloc(4, sizeof(int));
// realloc: 调整已分配内存块的大小
int* p3 = (int*)realloc(p2, sizeof(int) * 10);
// 注意:realloc成功后,原指针p2可能已经失效
// 这里不需要free(p2),因为realloc会处理原内存块
free(p1);
free(p3); // 只需要释放realloc返回的新指针
}C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因 此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。
void Test()
{
// 动态申请一个int类型的空间(不初始化)
int* ptr4 = new int;
// 动态申请一个int类型的空间并初始化为10
int* ptr5 = new int(10);
// 动态申请3个int类型的连续空间
int* ptr6 = new int[3];
// 正确释放内存
delete ptr4;
delete ptr5;
delete[] ptr6; // 注意:数组使用delete[]
}重要注意事项:
new和deletenew[]和delete[]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]; // 调用10次构造函数
free(p5); // 不调用析构函数
delete[] p6; // 调用10次析构函数
return 0;
}注意:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与 free不会。
new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是 系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过 operator delete全局函数来释放空间。
/*
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;
}
/*
free的实现
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)关键点:
operator new实际上是通过malloc来申请空间std::bad_alloc异常,而不是返回NULLoperator delete最终通过free来释放空间如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是: new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申 请空间失败时会抛异常,malloc会返回NULL。
new的原理
delete的原理
new TN的原理
delete[]的原理
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
使用格式:
new (place_address) type或者new (place_address) type(initializer-list)
place_address必须是一个指针,initializer-list是类型的初始化列表
使用场景:
定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如
果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。
class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A():" << this << endl;
}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
// 定位new/replacement new
int main()
{
// p1现在指向的只不过是与A对象相同大小的一段空间,还不能算是一个对象,因为构造函数没
有执行
A* p1 = (A*)malloc(sizeof(A));
new(p1)A; // 注意:如果A类的构造函数有参数时,此处需要传参
p1->~A();
free(p1);
A* p2 = (A*)operator new(sizeof(A));
new(p2)A(10);
p2->~A();
operator delete(p2);
return 0;
}主要用于内存池等场景,在预分配的内存上构造对象。
class A
{
public:
A(int a = 0) : _a(a)
{
cout << "A():" << this << endl;
}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
int main()
{
// 方法1:使用malloc分配内存,定位new构造对象
A* p1 = (A*)malloc(sizeof(A));
new(p1)A; // 在p1指向的内存上调用构造函数
p1->~A(); // 显式调用析构函数
free(p1);
// 方法2:使用operator new分配内存
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 |
|---|---|---|
语言性质 | C语言函数 | C++操作符 |
初始化 | 不初始化内存 | 可以初始化 |
大小计算 | 需手动计算并传递 | 自动计算类型大小 |
返回值 | void*,需要强制转换 | 返回正确类型的指针 |
失败处理 | 返回NULL,需判空 | 抛出异常,需捕获 |
自定义类型 | 不调用构造/析构函数 | 自动调用构造/析构函数 |
内存分配 | 只分配原始内存 | 分配内存并初始化对象 |
使用便捷性 | 相对繁琐 | 更加简洁安全 |
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。