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++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。
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
*/