C/C++内存分布
- 栈又叫堆栈,主要存放非静态局部变量、函数参数、函数返回值,栈一般是向下增长的
- 堆用于程序运行时动态内存分配
- 数据段用于存储全局数据和静态数据
- 代码段用于存储可执行代码和制度常量
C++内存管理方式
C语言的内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且用起来很麻烦
因此C++通过new和delete****操作符进行动态内存管理
内置类型
int main()
{
// 动态申请一个int类型的空间
int* ptr1 = new int;
// 动态申请一个int类型的空间并初始化为10
int* ptr2 = new int(10);
// 动态申请十个int类型的空间
int* ptr3 = new int[10];
delete ptr1;
delete ptr2;
delete[] ptr3;
return 0;
}
注意:申请和释放单个元素的空间,使用new
和delete
操作符,申请和释放连续的空间,使用new[]
和delete[]
。如果使用new[]
申请空间,使用delete
可能会造成内存泄漏
自定义类型
class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A():" << endl;
}
~A()
{
cout << "~A()" << endl;
}
private:
int _a;
};
int main()
{
A* p1 = (A*)malloc(sizeof(A));
A* p2 = new A(1);
free(p1);
delete p2;
return 0;
}
调用上述程序可以得到,在申请自定义类型的空间时,new
会调用构造函数,delete
会调用析构函数,而malloc
和free
不会
malloc/free和new/delete的区别
malloc
和free
是函数,new
和delete
是操作符malloc
申请的空间不会初始化,new
可以初始化malloc
申请空间时,需要手动计算空间大小并传递,new
只需跟上空间的类型即可,如果是多个对象,[]中指定对象个数即可malloc
的返回值是void*
,使用时必须强转,new
不需要malloc
申请空间失败时,返回的是NULL
,因此使用时必须判空,new
不需要,但是**new
必须捕获异常**- 对于自定义类型,
malloc
和free
只会开辟空间,不会调用构造函数和析构函数,而new
和delete
申请后或销毁前会调用构造和析构函数
总的来说,new
和free
使用会更加方便
new和delete的实现原理
内置类型
malloc
/free
和new
/delete
基本类似
自定义类型
- new的原理
- 调用operator new函数申请空间(底层还是通过malloc申请,相当于封装了一层)
- 在申请的空间上调用构造函数
- delete的原理
- 在空间上执行析构函数,完成对象中资源的清理
- 调用operator delete函数释放对象的空间(底层是通过free释放空间)
定位new表达式
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象,也就是显示调用构造函数
使用情景:内存池,因为内存池分配的内存没有初始化,如果是自定义类型的对象,需要使用new的定义表达式显示调用构造函数进行初始化
格式:new (place_address) type
或new(place_address) type(initializer-list)
place_address
必须是一个指针,initializer-list是类型的初始化列表
class A
{
public:
A(int a = 0)
: _a(a)
{
std::cout << "A()" << this << std::endl;
}
~A()
{
std::cout << "~A()" << this << std::endl;
}
private:
int _a;
};
int main()
{
A* pa = (A*)malloc(sizeof(A));
new(pa)A; // 如果A类的构造函数有参数时,此处需传参
pa->~A();
free(pa);
return 0;
}