目录
为什么new是先开空间再调用构造函数而delete先调用析构函数再释放空间?
定位new(显示调用析构函数)
new和delete
1.动态申请内置类型的数据
new和malloc除了语法上面,其它方面没什么区别,new可以在后面跟初始化
2.动态申请自定义类型的数据
new/malloc除了语法上面,还有一个最大区别
new调用构造函数初始化
delete调用析构函数清理
new和delete
一定要匹配使用,否则会产生未定的错误
()初始化
[]对象个数
#include<iostream>
using namespace std;
class A
{
public:
//A(int a = 0)
A(int a = 0, int b = 0)
: _a(a)
{
cout << "A():" << this << endl;
}
A(const A& aa)
: _a(aa._a)
{
cout << "A(const A& aa):" << this << endl;
}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
new和delete底层原理
先来看这段代码,在这里operator new 可以当成malloc使用,operator delete可以当成free使用
new和delete的底层汇编代码
new开空间时,先调用了operator new,再调用构造函数
delete释放空间时,先调用的析构函数,再调用operator delete
面向对象的语言处理失败,不喜欢用返回值,更建议用抛异常
malloc失败返回空
X86 32位
X64 64位
捕获抛异常
没有释放内存的话,之前申请的会一直在堆区
为什么new是先开空间再调用构造函数而delete先调用析构函数再释放空间?
我们拿stack来举例子
定位new
对已有的空间调用构造函数,因为malloc不会初始化
在这里,用new显示调用了构造函数进行初始化,模拟了new的实现
指针不能调用成员函数?
然后后面又显示调用了析构函数,因为p1是指针,它是内置类型,不会自动调用析构函数,自定义类型才会自动调用析构函数
应用
内存池,直接从内存池取出内存,是不会调用函数初始化的,因此需要我显示调用构造函数初始化,但是构造函数不能显示调用,因此需要用到定位new
malloc/free和new/delete的区别
内存泄漏
危害
其实在普通程序中,内存泄漏危害不大,因为进程结束后,操作系统会自动释放内存
最怕的是那种长期在线的服务器,并且有内存泄漏的程序,内存一次泄漏特别多还能很快发现,最难受的是不多,比如一天就几十M,然后有一天服务器就挂掉了,
打印申请内存的地址
如果不给初始化直接打印,会陷入死循环,因为字符串已'\0'作为结束标志。
int main()
{
char* p1 = new char;
cout << &p1 << endl;
cout <<(void*)p1 << endl;
return 0;
}
int main()
{
int* p1 = new int;
cout << p1 << endl;
cout <<(void*)p1 << endl;
return 0;
}
可以使用智能指针预防内存泄漏发生
模板
函数模板+类模板
两种写法:
template<typename T> 模板参数定义的是类型
templete<class T>
T是type的缩写
错误写法:
但是这样写是
templete<class T,typename T>
错误的
函数模板
这里有一个问题?30行和31行调用的是否是同一个函数?
从汇编代码中我们可以看到调用的不是同一个函数
通过参数推演,调用模板实例化生成的函数,编译器生成的
模板参数(形参),通过推演变成实参。
不仅内置类型可以推演,自定义类型也可以推演
指针也可以直接推演,进行交换,这里的swap是库里面的函数
库里面的交换函数swap
可以直接调用库里面的函数进行交换