文章目录
C/C++内存管理
1. C/C++内存分布
C++兼容C,因此内存分布都是一样的:
栈区:局部变量;堆区:malloc、calloc、realloc出来的对象
在const char* p1 = "abcd"和char str[] = "abcd"中,p1和str以及*p1和 *str分别存放在什么地方?
p1和str都是局部变量,都是存放在栈区;p1指向的"abcd"是存放在代码段的,所以p1是指向的代码段,*p1就是’a’字符,是存放在代码段的,所以 *p1是存放在代码段的,但是str是数组,"abcd"必须拷贝一份放在栈区,所以 *str是存放在栈区的
2. C++中动态内存管理
为什么需要内存管理?
对内存进行分类,这样操作系统对内存会更好的进行管理
2.1 new与delete操作内置类型
2.2 new与delete操作自定义类型
总结
C++的new和delete内存管理和C语言的mallloc和free最大的区别是:对于自定义类型来说,除了开空间外,C++的内存管理方式还调用了构造函数和析构函数。
3. operator new 和 operator delete函数
new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。
Visual studio 2019中operator new底层实现
void* __CRTDECL operator new(size_t const size)
{
for (;;)
{
if (void* const block = malloc(size))
{
return block;
}
if (_callnewh(size) == 0)
{
if (size == SIZE_MAX)
{
__scrt_throw_std_bad_array_new_length();
}
else
{
__scrt_throw_std_bad_alloc(); //抛出异常
}
}
// The new handler was successful; try to allocate again...
}
}
Visual studio 2019中operator delete底层实现
void __CRTDECL operator delete(void* const block, size_t const) noexcept
{
operator delete(block);
}
void __CRTDECL operator delete(void* const block) noexcept
{
#ifdef _DEBUG
_free_dbg(block, _UNKNOWN_BLOCK);
#else
free(block);
#endif
}
Visual studio 2019中operator new[]底层实现
void* __CRTDECL operator new[](size_t const size)
{
return operator new(size); //原理调用的size次operator new函数
}
Visual studio 2019中operator delete底层实现
void __CRTDECL operator delete[](void* const block) noexcept
{
operator delete(block);
}
void __CRTDECL operator delete[](void* const block, size_t const) noexcept
{
operator delete[](block);
}
总结
-
new和delete的本质:malloc和free的封装
-
new和malloc的机制:new失败了抛异常,malloc失败了返回NULL
-
对于内置类型,new和malloc以及delete和free类似,不同的地方在于new失败了抛异常,malloc失败了返回NULL
-
对于自定义类型,new的原理:1.调用operator new函数申请空间 2.调用构造函数
-
对于自定义类型,delete的原理:1.调用析构函数 2.调用operator delete函数释放空间
-
对于自定义类型,new object[Number] 的原理:1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请 2. 在申请的空间上执行N次构造函数
-
对于自定义类型吗,delete[]的原理:1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理 2.调用operator delete[]释放空间,实际在operator delete[]中调用N次operator delete来释放空间
-
new和delete必须匹配使用,不要new和free以及malloc和delete交叉使用
4. 定位new表达式
4.1 背景
class A
{
public:
A(int a)
:_a(a)
{
cout << "A()" << endl;
}
~A() {
cout << "~A()" << endl;
}
private:
int _a;
};
int main()
{
A* p = (A*)malloc(sizeof(A));
if (p == nullptr) {
perror("malloc is failed");
exit(-1);
}
//想对已经定义好的对象初始化怎么做?
return 0;
}
解决方案:
class A
{
public:
A(int a)
:_a(a)
{
cout << "A()" << endl;
}
~A() {
cout << "~A()" << endl;
}
private:
int _a;
};
int main()
{
A* p = (A*)malloc(sizeof(A));
if (p == nullptr) {
perror("malloc is failed");
exit(-1);
}
new(p)A(1); //定位new
return 0;
}
4.2 基本语法
定位new表达式是:在已分配的原始内存空间中调用构造函数初始化一个对象
使用格式:new(指针)type或者new(指针)type(初始化列表)
使用场景:一般配合内存池使。因为内存池分配出的内存没有初始化,所以如果定义自定义类型对象,需要使用new的定义表达式进行显示调用构造函数进行初始化