小编是双非本科大一菜鸟不赘述,欢迎大佬指点江山(QQ:1319365055)
此前博客点我!点我!请搜索博主 【知晓天空之蓝】
非科班转码社区诚邀您入驻
小伙伴们,打码路上一路向北,背后烟火,彼岸之前皆是疾苦
一个人的单打独斗不如一群人的砥砺前行
这是我和梦想合伙人组建的社区,诚邀各位有志之士的加入!!
社区用户好文均加精(“标兵”文章字数2000+加精,“达人”文章字数1500+加精)
直达: 社区链接点我
倾力打造转码社区微信公众号
程序员都喜欢 面向对象编程,但如果你没有对象怎么办?当然是 new 一个对象出来!
new其实就是告诉计算机开辟一段新的空间,但是和一般的声明不同的是,new开辟的空间在堆上,而一般声明的变量存放在栈上。new出来的是一段空间的首地址,所以一般需要用指针来存放这段地址:
A a; // a存在栈上
A* a = new a(); // a存在堆中
其实 new 的用法除了要调用对象的构造函数,其他的属性和我们的 malloc ,calloc ,realloc 是一模一样。既然 malloc 完了需要 free 掉,那 new 也需要我们手动释放毕竟是在堆区申请的,delete 也是同样的道理,先调用析构函数再释放对象空间。当然不用 new 的话系统会自动回收空间:
delete []a;
delete a;
C++中 delete a 和 delete[] a 对于内置类型对象没有任何区别
虽然 new 与 malloc 差别不大但我还是推荐使用 new ,毕竟更加简洁明了,而且 malloc 有时会面临对象不好初始化 ,如果对象包括私有类型成员且无法显式调用构造函数会生成随机值,比如构造一个栈:
class Stack
{
private:
int* a;
int top;
int capacity;
};
int main()
{
Stack* p1 = (Stack*)malloc(sizeof(Stack));
assert(p1);
Stack* p2 = new Stack;
}
因为 new 完会调用构造函数初始化,不用我们劳神费力,而且后续处理时,free 会直接干掉 Stack 这块空间,但是里面的成员还有指针类型,无法得到释放就会造成内存泄漏,delete 就会聪明的调用析构函数来解决这个问题。
对于内置类型,new 和 malloc,delete 和 free 基本一样,不同的是 new、delete 对应单个元素空间,new[] 和 delete [] 对应连续的空间。
delete 和 delete[] 两种方式体现出具体差异 ,前者仅仅释放掉 a 指向的全部内存,但是只调用了 a[0] 的析构函数,对于 a[1] 及后续成员我们习性分配的空间将不作处理从而导致内存泄漏。对于后者,会释放 a 指向的内存并逐一调用每个成员的 destructor(析构函数)。对于像 int,char,int*,struct 等等简单数据类型,由于对象没有 destructor,所以用 delete 和 delete [] 是一样的。
一般情况下, malloc 和 new 都不会失败,除非你开的非常大,但如果失败了,二者失败的各不相同,malloc 会返回一个空指针,而 new 会报错,我们针对 malloc 失败会采取 assert 策略,同样的针对 new 失败会进行异常捕获
catch (const exception& p)
{
cout << p.what() << endl; //抛异常
}
如果失败控制台就会给出 “ bad allocation” 字样提示开辟异常。
new 和 delete 是我们进行动态内存申请和释放的操作符,operator new/delete 是系统提供的全局函数,operator new() 是对new的重载形式,它是一个函数,并不是运算符。
对于operator new来说,分为全局重载和类重载,全局重载是 void* :: operator new(size_t size),在类中重载形式 void* A :: operator new(size_t size),他实际上是相当于对 malloc 和 malloc 抛异常进行了封装。
他的意义其实在于 new 的底层原理,new 调用其实就是 call malloc 再 call 对象的构造函数,但其实这并不符合 C++ 的需求,malloc 失败就会返回空,而 C++ 是面向对象不允许这种情况发生,于是引入了异常机制,会先去 call operator new。
C++ 比较恶心的机制,我们 new[] 的话会多次调用 call operator new,再 call malloc,再 call 构造函数,绕了好多层去找堆,路程很远消耗很大,如果再频繁调用成本就抬高了,我们有个东西叫内存池,他比堆离得更近,有些地方甚至比堆还快。打个比方,情人节你给你女朋友发红包,堆就像小红包,你每次发 1 元掉你女朋友胃口,很难不分手快乐,而内存池就像微信转账,直接一个快准狠的 520 给拿捏了。
也称定位 new 表达式,在已分配的原始内存空间中调用构造函数初始化一个对象。其格式为:new(place_address)type 或者 new(place_address) type (initializer-list) ,其中 place_address 必须是一个指针,initializer-list 是类型的初始化列表。
他的使用场景一般就是配合内存池使用,因为内存池分配出的内存没有初始化,所以如果是自义定类型空间对象,需要 new 的定义表达式进行显式构造函数进行初始化,直接使用 new 就会直接去到堆区,无法去我要找的空间。
C++程序中一般关心两个方面的内存泄漏:堆内存泄漏和系统资源泄露
堆内存泄漏指程序执行中依据需要用 malloc,calloc,realloc,new 的方式从堆中分配一块内存,但是用完后并没有 free 或者 delete 进行归还,这部分内存没有被释放掉,你访问不到,系统也无法将其再分配。
系统资源泄露指程序使用系统分配的资源,比如套接字,文件描述符,管道等没有使用对应函数释放掉,导致系统资源浪费,严重可导致系统效能减少,执行不稳定。
我们在Linux环境中有一款强大的开源内存检测工具——valgrind,他里面的 Memcheck 是valgrind使用最广泛的工具,一个重量级的内存检测器,能够发现绝大多数内存错误使用情况。
今天就到这里吧,润了家人们。