Lesson05--C/C++内存管理

  • 1. C/C++内存分布
  • 2. C语言中动态内存管理方式
  • 3. C++中动态内存管理
  • 4. operator newoperator delete函数
  • 5. newdelete的实现原理
  • 6. 定位new表达式(placement-new)
  • 7. 常见面试题

1. 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);
}

1. 选择题: 


选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
globalVar在哪里?__(1)__ staticGlobalVar在哪里?__(2)__
staticVar在哪里?__(3)__ localVar在哪里?__(4)__
num1 在哪里?__(5)__

 1.C:全局变量都在静态区

 2.C:

3.C:用static修饰的局部变量也在静态区

4.A:局部变量都在栈上        

5.A

char2 在哪里? ____ * char2 在哪里? ___
pChar3 在哪里? ____ * pChar3 在哪里? ____

ptr1在哪里?____ *ptr1在哪里?____  

1. A:char2还是一个数组它就在栈上

2.A:*char2,数组名解引用结果是数组的第一个,所以还是在栈上

3.A:pchar3是一个指针类型所以也是在栈上

4.D:pChar它解引用是"abcd",通过解引用以后也无法对原来的数据进行修改,"abcd"本质就是代码段

5.A:也是一个指针类型,所以在栈上

6.B:malloc的都是在堆上

2. 填空题:

sizeof ( num1 ) = ____ ;
sizeof ( char2 ) = ____ ; strlen ( char2 ) = ____ ;
sizeof ( pChar3 ) = ____ ; strlen ( pChar3 ) = ____ ;
sizeof ( ptr1 ) = ____ ;

 sizeof(num1) = 40

sizeof数组名是整个数组的大小

sizeof(char2) =5

四个字符以外还有'\0',也是一个字符

 strlen(char2)=4

sizeof(pChar3) = 8,32位下就是4,这里是一个指针的大小

strlen(pChar3) = 4

sizeof(ptr1) = 4

3. sizeof strlen 区别?

  • sizeof 用于获取类型或对象的内存大小,包括字符串结束符。
  • strlen 用于获取字符串的实际字符长度,不包括结束符。

2. C语言中动态内存管理方式:malloc/calloc/realloc/free 

void Test ()
{
int* p1 = (int*) malloc(sizeof(int));
free(p1);
// 1.malloc/calloc/realloc的区别是什么?
int* p2 = (int*)calloc(4, sizeof (int));
int* p3 = (int*)realloc(p2, sizeof(int)*10);
// 这里需要free(p2)吗?
free(p3 );
}
【面试题】
1. malloc/calloc/realloc 的区别?
malloc不会初始化
calloc会初始化成0
2. malloc的实现原理?

3. C++内存管理方式  

C 语言内存管理方式在 C++ 中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此 C++ 又提
出了自己的内存管理方式: 通过 new delete 操作符进行动态内存管理

3.1 new/delete操作内置类型 

int main()
{
	int* p1 = (int*)malloc(sizeof(int));
	int* p2 = new int;

	free(p1);
	delete p2;
}

 这俩种写法是等价的

int main()
{
	int* p1 = new int;
	int* p2 = new int[10];

	delete p1;
	delete[] p2;

}

多个的这样写就行

还可以进行初始化

 单个的用()括号进行初始化,多个的用{}用来初始化,没有初始化的部分全部初始化成0

 

 注意:申请和释放单个元素的空间,使用newdelete操作符,申请和释放连续的空间,使用new[]

delete[] ,注意:匹配起来使用。

3.2 newdelete操作自定义类型  

class A
{
public:
	A(int a=0,int b=0)
	{
		_a = a;
		_b = b;
	}

private:
	int _a;
	int _b;
};

int main()
{
	A* p1 = new A;
	A* p2 = (A*)malloc(sizeof(A));
}

 

可以看见一个会掉构造函数一个不会

甚至new的还可以用初始化列表的初始化方法来初始化

 类的成员变量都是私有的那么在想去初始化就不行了

 创建多个的话每一个都会调用构造函数和析构函数

多参数用{}就可以了

// new/delete malloc/free 最大区别是 new/delete 对于【自定义类型】除了开空间还会调用构
造函数和析构函数
注意:在申请自定义类型的空间时, new 会调用构造函数, delete 会调用析构函数,而 malloc free 不会

4. operator newoperator delete函数(重要点进行讲解)

 4.1 operator newoperator delete函数(重点)

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)

 new是操作符,malloc是函数,new底层其实就是封装malloc,new会调用构造函数,会抛出异常

5. newdelete的实现原理 

5.1 内置类型

如果申请的是内置类型的空间, new malloc delete free 基本类似,不同的地方是: new/delete 申请和 释放的是单个元素的空间,new[] delete[] 申请的是连续空间,而且 new 在申请空间失败时会抛异常, malloc会返回 NULL

 5.2 自定义类型

  • new的原理
        1. 调用 operator new 函数申请空间
        2. 在申请的空间上执行构造函数,完成对象的构造
  • delete的原理
        1. 在空间上执行析构函数,完成对象中资源的清理工作
        2. 调用 operator delete 函数释放对象的空间
  •  new T[N]的原理
        1. 调用 operator new[] 函数,在 operator new[] 中实际调用 operator new 函数完成 N 个对象空间的申请
        2. 在申请的空间上执行 N 次构造函数

  • delete[]的原理
        1. 在释放的对象空间上执行 N 次析构函数,完成 N 个对象中资源的清理
        2. 调用 operator delete[] 释放空间,实际在 operator delete[] 中调用 operator delete 来释放空间

通过汇编可以看到这里用了44字节的内存,10个整形应该是40字节啊,多的4的字节拿去干嘛了?

多的4的字节拿来保存10了,这里是为了析构函数

 delete[]里面就是缺省的上面的10,这里就会调用10次析构函数

 

 改变参数,可以发现这里跟着改变了

 delete[]向前偏移数,这里多的4的字节就是对象个数,方便delete去,知道有多少个对象去调用析构函数

这里可以得出一个结论,malloc就和free配套使用,new就和delete使用,要不然可能会有各种各样的问题

6. 定位new表达式(placement-new) (了解)  

定位 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;
}

7. 常见面试题

7.1 malloc/freenew/delete的区别  

malloc/free new/delete 的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的地方是:
  • 1. mallocfree是函数,newdelete是操作符
  • 2. malloc申请的空间不会初始化,new可以初始化 
  • 3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可, 如果是多个 对象,[]中指定对象个数即可
  •  4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
  • 5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常 
  • 6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间 后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值