2021-10-21面向对象:动态分配所得的内存块笔记

2021-10-21面向对象:动态分配所得的内存块笔记

此笔记中皆是在VC编译器的情况

new和delete

Complex class:

class Complex
{
    
    
    public : 
        Complex() {
    
    }
    private :
        double m_real;//实部
        double m_imag;//虚部
};
Complex* p = new Complex();

对于Complex p = new Complex();*编译器转化为如下

//1.分配内存,调用malloc(n)函数申请内存
void*mem = operator new(sizeof(Complex));
//2.类型转换
p = static_cast<Complex*>(mem);
//3.构造函数
pc->Complex::Complex(1,2);//Compelx::Complex(pc,1,2),pc一般默认不写,在函数中直接用this来表示
class String
{
    
    
public:                                 
   String(const char* cstr=0){
    
    	
   	    if (cstr) {
    
    
	      m_data = new char[strlen(cstr)+1];
	      strcpy(m_data, cstr);
   	  }else{
    
       
	      	m_data = new char[1];
	      	*m_data = '\0';
   		}
   }                         
   ~String(){
    
    delete[] m_data;}                                   
private:
   char* m_data;
};
String* ps = new String("hello");
delete[] ps;

对于*delete[] p;*编译器转化步骤如下:

//delete: 先调用析构函数再释放内存
//1.调用析构函数
String::~String();
//2.释放内存
operator delete(ps);//内部调用free()函数

动态分配所得的内存块大小

Complex的data部分有两个double类型的变量,内存大小是8字节,实际在VC编译器下申请到的内存大小如下图所示

所以在调试模式下,实际上指针p总共获得的内存大小是64个字节。

除了Complex类的data部分共8个字节(此处一个double4字节),在调试状态下VC编译器额外分配32+4个字节,还有两个在头尾的主要记录整块内存信息的cookie共8字节,加起来一共52字节,因为在VC编译器中,VC给的每一个区块都是16的倍数,所以,给到的最终内存块大小总共大小要是16的倍数,进而此处还要增加12个字节,使52字节变成64字节。

关于除去本身data部分的内存,其余的内存分配不是浪费,是为了更好地回收内存。

关于cookie : 主要是记录分配所得的内存的大小,让系统知道回收这整块内存的大小,表示的都是16进制的数,在此例子中,该整块内存大小为64个字节,转换16进制便是40,最后一位变成1表示这个内存以及分配出去。为什么是16进制呢?因为内存块大小都是16的倍数,由16进制表示的话最后一位的数字必定是0,便于用最后一位数字来标记内存是否分配出去。

如果不是在调试状态下的话,就没有额外分配的32+4字节内存,如下图所示
在这里插入图片描述
由于16是16的倍数所以无需补充内存

动态分配所得的array内存大小

Complex* p = new Complex[3];

内存块中会增加4字节来记录array的个数

array new 一定要搭配array delete

如果使用array new一定要搭配array delete,否则容易发生内存泄漏。
在上面的类String动态分配内存中使用array new 即 String ps = new String(“hello”);* 则就要配合使用array delete 即 delete[ ] ps

如果缺少[ ]执行的是delete ps,则会出现一些指针所指向的内存区域未被清除导致内存泄漏。

String使用array new 时分配的内存大小如下(非调试模式下):
在这里插入图片描述

当使用delete是delete ps而不是delete[ ] ps时,析构函数被调用,然后释放内粗——根据cookie的信息判断要删除的A的整块大小,因此A处有无[ ]都会被整块清除掉因为cookie的信息不会因为是不是array delete而变化。然而当有[ ]才会让编译器知道要调用三次析构函数来把每个string object所获得的内存B(a、b、c)清除掉,而没有delete的话,析构函数只被调用一次,只清除掉了A和a,导致剩下的b和c没有被清除掉,从而导致内存泄漏。

Complex与String相比,虽然Complex* p =new Complex[3]中没有指针指向别的内存区域,即使detele p也不会发生内存泄漏,申请的内存也会根据cookie的信息整块删除掉,但是使用了arrray new就要搭配array delete来使用可以以防万一导致内存泄漏,养成好习惯。

知识来源:
侯捷C++面向对象高级开发:8.堆,栈与内存管理

猜你喜欢

转载自blog.csdn.net/weixin_44848852/article/details/120897140