文章目录
new&delete
****c语言中使用malloc,realloc,calloc关键字来开辟动态空间
c++兼容c语言,对于内置类型尤其是自定义类型的动态申请,简化用法,功能一致
calloc可以设置初始值,但繁琐
格式new加类型返回指针
自动计算大小,不需要强转
new开辟空间,调用构造函数初始化(多个数据,多次调用构造函数)
delete释放空间,调用析构函数(多个数据,多次调用析构函数)
int main()
{
//功能一致,用法简化
int *ptr1=(int *)malloc(sizeof(int));
int *ptr2=new int;
int *ptr3(int *)malloc(sizeof(int)*10);
int * ptr4=new int[10];
//销毁
free(ptr1);
free(ptr3);
//指针是内置类型不会自动调用析构函数
delete ptr3;
delete[] ptr4;
//new额外支持开空间和初始化
//初始化
int* ptr5=new int(10);
//多个对象
int* ptr6=new int[10];
//数组
int* ptr7=new int[10]{1,2,3,4,5};
int* ptr8=new int[10]{};
//错误
int* ptr9w int [10]=1,2,3,4,5};
return 0;
}
相对于内置类型new和malloc没什么区别,new最重要的是针对自定义类型,c语言中malloc对于开辟空间基本上没办法使用,无法调用构造函数
new[]&delete[]
调用多次构造和多次析构
class A
{
public:
A(int a)
:_a(a)
{}
private:
int _a;
};
int main()
{
A A1(1);
A A1(2);
//有名对象
A* ptr1=[5]{A1,A2};
delete[] ptr1;
//匿名
A* ptr2=[5]{A(1),A(2)};
delete[] ptr2;
//隐式类型转换
A* ptr3=[5]{1,2};
delete[] ptr3;
return 0;
}
不匹配
不匹配未定义行为报错
class A
{
public:
A(int a)
:_a(a)
{}
~A()
{
;
}
private:
int _a;
};
int main()
{
A* a1=new A;
delete a1;
A* a2=new A[10];
delete[] a2;
A* a3=new A[10];
delete a3;
//a3的不匹配行为不会造成,内存泄漏
//但是如果显示定义析构,申请空间会在前面多申请存储个数值
//指针会指向错误
//没有调用析构是不会报错
return 0;
}
一定要匹配使用
class A
{
public:
A(int a)
:_a(a)
{}
~A()
{
;
}
private:
int _a;
};
int main()
{
int * p=new int[10];
//在存在delete[]时
//实际上开辟sizeof(int)*10+4,这四字节负责记录个数,而指针p指向这四字节后的第一个地址
//当它释放空间时,调用析构根据前四字节的数据调用n次析构函数
//调用operator delete,会将指针向前偏移,然后释放整个空间
delete[] p;
A* p1=new A[10];
//自定义类型A,没有显示定义析构函数,而编译器生成的默认析构函数因为没资源清理,就没有调用,直接返回首地址的位置
delete p1;
return 0;
}
operator new函数&operator delete函数
这两个是库函数并不是重载
new是由operator new函数来开辟空间
delete是由operator delete函数来释放空间
operator new和operator delete是对malloc与free的封装
int main()
{
Stack* pst1=(Stack*)operator new(sizeof(Stack));
Stack* pst2=new Stack;
return 0;
}
new T[n];
//调用operator new[]函数,在operator new[]调用operator new完成对N个对象空间的申请
//在申请的空间上执行n次构造函数
delete[];
//在释放的对象空间上执行n次析构函数,完成n个对象中资源的清理
//调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间
定位new
定位new表达式(placement-new)替换new
定位new通常是配合内存池来使用的
**STL自建内存池(池化技术)**将某些重复使用的资源放在内存池,相对于在堆中调用更快,(内存还是从堆里分配的)
格式new(指针)类型(参数列表)
int main()
{
//和malloc使用方法一样
Stack* pst=(Stack*)operator new(sizof(Stack));
pst->pst(5);//无法显示调用构造
new(pst)Srack(5);//显示调用构造函数
return 0;
}
异常
抛异常,一般情况下申请空间不会出现异常,但当申请空间过大时就会出现问题
new申请失败会抛异常,出现抛异常后就需要捕获异常
只有在try,catch内才会捕获异常
int main()
{
//捕获异常
try
{
char* p1=new char[1000000000];
//cout将p1当做字符串打印,但是指针没有/0
//所以可以将p1强制类型转换
cout<<(void*)p1<<endl;
}
//执行流跳跃出现异常会直接跳转到catch函数,无视后面语句
//异常会被exception类型获取
catch(cosnt exception& e)
{
//可以通过what获知错误信息
cout<<e.what()<<endl;
}
return 0;
}
malloc/free&new/delete的区别
malloc和free是函数,new和delete是操作符
malloc申请的空间不能初始化,new可以初始化
malloc使用繁琐,new简化
malloc返回void*,new返回空间的类型
malloc申请失败返回空,需要判空,new申请失败抛异常,需要捕获异常
申请自定义类型对象时,malloc,free只会开辟空间,不会调用构造函数与析构函数,而new申请空间会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理
内存泄漏
没有释放内存就是内存泄漏
普通内存泄露不会有什么危害,系统会自己回收
但是对于长期运行的程序却有很大的危害
内存分布
堆 自由申请空间
栈 函数调用建立栈帧,存储局部变量
静态区(数据段)
常量区(代码段)