C && CPP 内存管理

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)吗?
//如果空间够的话我们这里realloc返回的指针就是p2
//free p2 会  double free
free(p3 );
}
三者都是分配内存,都是stdlib.h库里的函数,但是也存在一些差异。

(1)malloc函数。其原型void *malloc(unsigned int num_bytes);
num_byte为要申请的空间大小,需要我们手动的去计算,如int *p = (int *)malloc(20*sizeof(int)),
如果编译器默认int为4字节存储的话,那么计算结果是80Byte,一次申请一个80Byte的连续空间,
并将空间基地址强制转换为int类型,赋值给指针p,此时申请的内存值是不确定的。
(2)calloc函数,其原型void *calloc(size_t n, size_t size);
其比malloc函数多一个参数,并不需要人为的计算空间的大小,比如如果他要申请20个int类型空间,
会int *p = (int *)calloc(20, sizeof(int)),这样就省去了人为空间计算的麻烦。但这并不是
他们之间最重要的区别,malloc申请后空间的值是随机的,并没有进行初始化,而calloc却在申请后,
对空间逐一进行初始化,并设置值为0;
#include<stdio.h>

#include <string>

#include<stdlib.h>

void main()
{
	int* p = (int*)malloc(20 * sizeof(int));
	int* pp = (int*)calloc(20, sizeof(int));
	int i;

	printf("malloc申请的空间值:\n\n");
	for (i = 0; i < 20; i++)
	{
		printf("%d ", *p++);
	}
	printf("\n\n");
	printf("calloc申请的空间的值:\n\n");
	for (i = 0; i < 20; i++)
	{
		printf("%d ", *pp++);
	}
	printf("\n");
}

(3)realloc函数和上面两个有本质的区别,其原型void realloc(void *ptr, size_t new_Size)
用于对动态内存进行扩容(及已申请的动态空间不够使用,需要进行空间扩容操作),ptr为指向原来空间
基址的指针, new_size为接下来需要扩充容量的大小。
实例:
int main(void)
{
    const int size = 21;
    int *p = (int *)malloc(20*sizeof(int));
    int *pp = (int *)realloc(p, size*sizeof(int));
    
    printf("原来的p_Address:%x   扩容后的pp_Address:%x \n\n", p, pp);
    
    return 0;
}

如果size较小,原来申请的动态内存后面还有空余内存,系统将直接在原内存空间后面扩容,
并返回原动态空间基地址;如果size较大,原来申请的空间后面没有足够大的空间扩容,
系统将重新申请一块(20+size)*sizeof(int)的内存,并把原来空间的内容拷贝过去,原来
空间free;如果size非常大,系统内存申请失败,返回NULL,原来的内存不会释放。注意:
如果扩容后的内存空间较原空间小,将会出现数据丢失,如果直接realloc(p, 0);相当于free(p).

 C++内存管理方式

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

void Test()
{
  // 动态申请一个int类型的空间
  int* ptr4 = new int;
  
  // 动态申请一个int类型的空间并初始化为10
  int* ptr5 = new int(10);
  
  // 动态申请10个int类型的空间
  int* ptr6 = new int[3];
  delete ptr4;
  delete ptr5;
  delete[] ptr6;
}

new和delete操作自定义类型

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
class A
{
public:
	A(int a = 0)
		: _a(a)
	{
		cout << " Create A():"<< "   " << this << endl;
	}
	~A()
	{
		cout << "Destory ~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)); // C
	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;
}

attention:在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,而malloc与 free不会。

class Test
{
public:
	Test():m_data(0)
	{
		cout<<"Test::Test()"<<endl;
	}
	~Test()
	{
		cout<<"Test::~Test()"<<endl;
	}
public:
	void InitTest()
	{
		m_data = 0;
		ptr = (int*)malloc(sizeof(int)*10);
		assert(ptr != NULL);
	}
	void DestroyTest()
	{
		free(ptr);
	}
private:
	int m_data;
	int *ptr;
};

void main()
{
	//Test t; //静态分配  栈区
	Test *pt = (Test*)malloc(sizeof(Test)); //申请空间
	assert(pt != NULL);
	pt->InitTest();                         //初始化对象

	pt->DestroyTest();                      //摧毁对象
	free(pt);                               //释放空间
}
-----------------------------------------------------------------------------------

以C的操作他是要调用方法来进行初始化,再调用方法进行摧毁,
class Test
{
public:
	Test(int data = 0):m_data(data)
	{
		cout<<"Test::Test()"<<endl;
		ptr = new int[10];
	}
	~Test()
	{
		cout<<"Test::~Test()"<<endl;
		delete []ptr;
	}
private:
	int m_data;
	int *ptr;
};

void main()
{
	Test *pt = new Test(1);
	delete pt;

	Test *pa = new Test[10];
	delete []pa;
}

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<assert.h>
#include<vld.h>
using namespace std;
class Test
{
public:
	Test(int data = 0) :m_data(data)
	{
		cout << "Test::Test()Creat" << endl;
		ptr = new int[10];
	}
	~Test()
	{
		cout << "Test::~Test()Destory" << endl;
		delete[]ptr;
	}
private:
	int m_data;
	int* ptr;
};

void main()
{
	Test* pa = new Test[10];
	delete[]pa;
}

----------------------------------------------------------------------------------------


c++会自动调用 默认构造函数   还有析构函数

等于 初始化 及 摧毁

ATTENTION

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

new operator

  new operator 指的就是new操作符,它分为两个阶段的操作:

(1)调用::operator new 申请内存(相当于C语言的malloc)

(2)调用类的构造函数

#include<iostream>
 using namespace std;

class Fun{
public:
    Fun(){ std::cout<<"call constructor"<<std::endl;}
    ~Fun(){ std::cout<<"call destructor"<<std::endl;}
};
 
Fun* ptr1 = new Fun;  
delete ptr1;
ptr1 = nullptr;
 
// 输出结果
// call constructor
// call destructor

operator new

        operator new操作符单纯申请内存,并且是可以重载的函数。调用operator new申请内存,内存申请的大小为自定义类Fun的大小。使用operator new 和 operator delete并不会调用构造函数和析构函数,因为其仅仅具有申请内存的功能
 

Fun* ptr2 = (Fun*)::operator new(sizeof(Fun));
::operator delete ptr2;
ptr2 = nullptr;
 
// 加上::代表的是全局,因为operator可以重载
// 此时编译器并不会输出call constructor和call destructor
// 由此可以证明operator仅具有申请内存的功能

(1)重载operator new 操作符:

class Fun{
public:
    Fun(){ std::cout<<"call constructor"<<std::endl;}
    ~Fun(){ std::cout<<"call destructor"<<std::endl;}
 
    void* operator new(size_t size)
    {
        std::cout<<"operator new"<<std::endl;
        return ::operator new(size);
    }
    void operator delete(void* ptr)
    {
        std::cout<<"operator delete"<<std::endl;
        ::operator delete(ptr);
        ptr = nullptr;
    }
};  
 
Fun* ptr3 = new Fun;  
delete ptr3;
 
// 此时输出的是:  
// operator new
// call constructor
// call destructor
// operator delete 

(2)operator new的另外一种重载版本:

class Fun{
public:
    Fun(){ std::cout<<"call constructor"<<std::endl;}
    ~Fun(){ std::cout<<"call destructor"<<std::endl;}
 
    void* operator new(size_t size)
    {
        std::cout<<"operator new"<<std::endl;
        return ::operator new(size);
    }
    void* operator new(size_t size, std::string str)
    {
        std::cout<<"operator new version 2: "<<str<<std::endl;
        return ::operator new(size);
    }
    void operator delete(void* ptr)
    {
        std::cout<<"operator delete"<<std::endl;
        ::operator delete(ptr);
        ptr = nullptr;
    }
};  
 
Fun* ptr4 = new("this is my func") Fun;  
delete ptr4;
 
// 此时输出的是:  
// operator new version 2: this is my func
// call constructor
// call destructor
// operator delete 

3、placement new

placement new 又称为定位new运算符,它能够让程序员指定需要使用的位置。定位new运算符直接使用传递给它的地址,它不负责判断哪些内存单元已被使用,也不查找未使用的内存块。这将一些内存管理的负担交给了程序员。

char* buf[128]; // 创建一块内存池
int* p1 = new(buf)int[10];
for(int i=0;i<10;++i)
    p1[i]=i+1;
 
std::cout<<"buf的地址:"<<(int*)buf<<std::endl;
std::cout<<"p1数组的地址:"<<p1<<std::endl;
 
int* p2 = new(buf)int;
std::cout<<"p2的地址:"<<p2<<std::endl;
 
int* p3 = new(buf+10*sizeof(int))int;
std::cout<<"p3的地址:"<<p3<<std::endl;
 
/*
    输出结果:
    buf的地址:0x7ffe318d6d70
    p1数组的地址:0x7ffe318d6d70
    p2的地址:0x7ffe318d6d70
    p3的地址:0x7ffe318d6eb0
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值