C++基础语法(内存管理)

简介: C++基础语法(内存管理)

我们在学习C语言的时候,可以在栈区中使用内存空间,但栈区的空间毕竟很有限而且随着栈的销毁,该栈里的数据都会被销毁掉。因此我们学习了堆,堆的空间比栈要大很多很多,并且堆区空间的数据,只要我们不主动释放,在程序中会一直保存,直到该程序停止运行

那么C语言中开辟堆空间的函数主要有三个,malloc,realloc,calloc这三剑客我们都很熟悉了,那么既然我们学习了C++,就要学习C++中动态开辟内存的函数,C++中动态开辟内存的只有new,虽然只有这一个,但是可并不是那么简单的,这篇博客,都将围绕着new来进行讲解,并解释new和C语言中的三剑客的区别


new和delete的用法

在C++中,我们可以继续使用C语言动态开辟内存三剑客,但是在一些情况下,就不是那么好用了,因此,C++设计了自己的动态内存开辟和释放的方式,那就是new和delete

C++中用new来开辟动态内存,如果是开辟单个元素的空间

那么我们直接使用new后面接上类型名就可以,看下面的示例代码

//开辟单个int类型的元素空间
int *p = new int;
//释放单个int类型的元素空间
delete p;
//开辟单个double类型的元素空间
double *p = new double;
//释放单个double类型的元素空间
delete p;

如果是开辟连续的元素空间,那么就可以使用new typename[n], "[]"中的n表示要开辟的元素的个数,typename表示数据类型名称

释放该连续空间时,使用delete [],看下面的实例代码

//开辟连续int类型的元素空间
int *p = new int[10];
//释放连续int类型的元素空间
delete[] p;
//开辟连续double类型的元素空间
double *p = new double[10];
//释放连续double类型的元素空间
delete[] p;

new和C语言动态开辟三剑客的区别

你可能会想,这和C语言的动态开辟内存有很大的区别吗?无非是写法变得简单了一些,有必要为此重新设计吗?

有这样的想法很正常,因为在开辟内置类型空间,比如double,int,char等时区别是不大,但是在开辟类的对象时,情况就不一样了,C语言中没有关于类的相关概念,因此用C语言的三剑客开辟并不会调用该类的构造函数,用free释放该内存空间时,也不会调用析构函数,这就会导致一个很严重的问题,类就没法正常使用了

但是使用new和delete就不一样了,使用new开辟一个类的内存空间时,会同时调用该类的构造函数,完成初始化工作,相应的,释放该内存空间时,也要用delete来释放,因为delete不仅会释放空间,同时会调用该类的析构函数,完成对类的释放,如果用new开辟一个类的内存空间而不用delete来释放,就可能会导致内存泄漏


new和delete的实现原理

上面我们说到在使用new和delete进行开辟和释放时,一定要匹配使用,例如使用new[]开辟了一段连续的内存空间,而使用delete而不是delete[]来释放,就很可能会造成程序崩溃,这是因为delete释放的底层实现决定的

如果你使用new开辟了单个元素空间,而使用delete[]来进行释放,那么delete会回退一个int空间,取一个随机值,然后释放,可能导致程序直接崩溃 

如果你开辟了一个类的一段连续内存空间,使用delete而不是delete[]来释放,那么程序会崩溃,而如果你屏蔽掉该类的析构函数,那么也有可能会编译通过,这是因为在delete空间时,如果你写了析构函数,那么在new的时候就会多开辟一个int类型的空间,来记录开辟元素的个数,再使用delete是不会回退一个int空间,这就少释放了一个int类型空间,从而编译报错。而你屏蔽掉析构函数之后,编译器自己生成析构函数,本来就什么都不干,编译器会认为析构不析构都无所谓,便偷懒,不再创建这个int类型的空间,这个时候再编译可能就不会再报错了

new和delete实际上是会在底层调用其他函数

使用new时会调用函数 operator new

使用new[]时会调用函数 operator new[]

delete也是如此

使用delete时会调用函数 operator delete

使用delete[]时会调用函数 operator delete[]

但是注意,这不是对new的操作符重载,而是这个函数名就叫operatorxxx

事实上new的底层实现仍然是调用malloc,只不过加了一层封装,可以返回异常,实现调用构造函数,同样的,delete底层也是在调用free


内存泄漏的原因及避免和检查方法

我们更加关注两个方面的内存泄漏

1.堆内存泄漏

堆内存泄漏多是因为我们使用malloc,realloc,new等在堆区开辟的内存空间,在使用完毕后没有及时释放掉,导致指向这块开辟空间的指针丢失,从而造成内存空间一直被占据,再也无法释放掉

也并不是说只要我们写了释放指令,就一定能够释放掉开辟过的内存空间,这个也与程序的逻辑结构有关,看下面一段程序

void test() {
    int* p = new int[10];
  //do something
  //do something
  if (/*xxx is true*/) {
    return;
  }
  //do something
  delete[] p;
  return;
}
int main() {
  test();
  return 0;
}

如果上述代码中if为真,你直接返回掉了,那么此时就会导致内存泄漏问题,即使你写了delete语句,但是因为程序逻辑结构导致这个语句并未执行就直接退出,从而造成了内存泄漏,可见内存泄漏要从多方面考虑,尤其是在提前退出返回的地方,要特别注意

2.系统资源泄漏

主要是指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定

这个就要求我们打开某些文件,一定要接上关闭函数,不然会导致资源一直被占用,一旦该资源的指针丢失,那么内存就会泄漏

如果程序中出现了内存泄漏的问题,我们可以使用相关的内存泄漏检测工具来检测哪里出了问题,但这样做不仅耗时耗力,而且很多工具都是收费使用,因此我们平时一定要养成良好的编程习惯,可以使用C++提供的智能指针,提前预防内存泄漏

目录
相关文章
|
2月前
|
存储 编译器 开发工具
01.C++基础语法
本教程系统讲解C++基础语法,涵盖语言特性、编译器使用、命名空间、头文件、修饰符与关键字等核心内容,助你快速掌握C++编程基础。
260 9
|
5月前
|
安全 C语言 C++
比较C++的内存分配与管理方式new/delete与C语言中的malloc/realloc/calloc/free。
在实用性方面,C++的内存管理方式提供了面向对象的特性,它是处理构造和析构、需要类型安全和异常处理的首选方案。而C语言的内存管理函数适用于简单的内存分配,例如分配原始内存块或复杂性较低的数据结构,没有构造和析构的要求。当从C迁移到C++,或在C++中使用C代码时,了解两种内存管理方式的差异非常重要。
221 26
|
10月前
|
存储 程序员 编译器
玩转C++内存管理:从新手到高手的必备指南
C++中的内存管理是编写高效、可靠程序的关键所在。C++不仅继承了C语言的内存管理方式,还增加了面向对象的内存分配机制,使得内存管理既有灵活性,也更加复杂。学习内存管理不仅有助于提升程序效率,还有助于理解计算机的工作原理和资源分配策略。
|
6月前
|
C语言 C++
c与c++的内存管理
再比如还有这样的分组: 这种分组是最正确的给出内存四个分区名字:栈区、堆区、全局区(俗话也叫静态变量区)、代码区(也叫代码段)(代码段又分很多种,比如常量区)当然也会看到别的定义如:两者都正确,记那个都选,我选择的是第一个。再比如还有这样的分组: 这种分组是最正确的答案分别是 C C C A A A A A D A B。
130 1
|
12月前
|
存储 缓存 编译器
【硬核】C++11并发:内存模型和原子类型
本文从C++11并发编程中的关键概念——内存模型与原子类型入手,结合详尽的代码示例,抽丝剥茧地介绍了如何实现无锁化并发的性能优化。
524 68
|
9月前
|
存储 Linux C语言
C++/C的内存管理
本文主要讲解C++/C中的程序区域划分与内存管理方式。首先介绍程序区域,包括栈(存储局部变量等,向下增长)、堆(动态内存分配,向上分配)、数据段(存储静态和全局变量)及代码段(存放可执行代码)。接着探讨C++内存管理,new/delete操作符相比C语言的malloc/free更强大,支持对象构造与析构。还深入解析了new/delete的实现原理、定位new表达式以及二者与malloc/free的区别。最后附上一句鸡汤激励大家行动缓解焦虑。
|
10月前
|
编译器 C语言 C++
☺初识c++(语法篇)☺
☺初识c++(语法篇)☺
|
10月前
|
安全 C语言 C++
彻底摘明白 C++ 的动态内存分配原理
大家好,我是V哥。C++的动态内存分配允许程序在运行时请求和释放内存,主要通过`new`/`delete`(用于对象)及`malloc`/`calloc`/`realloc`/`free`(继承自C语言)实现。`new`分配并初始化对象内存,`delete`释放并调用析构函数;而`malloc`等函数仅处理裸内存,不涉及构造与析构。掌握这些可有效管理内存,避免泄漏和悬空指针问题。智能指针如`std::unique_ptr`和`std::shared_ptr`能自动管理内存,确保异常安全。关注威哥爱编程,了解更多全栈开发技巧。 先赞再看后评论,腰缠万贯财进门。
467 0
|
11月前
|
存储 程序员 编译器
什么是内存泄漏?C++中如何检测和解决?
大家好,我是V哥。内存泄露是编程中的常见问题,可能导致程序崩溃。特别是在金三银四跳槽季,面试官常问此问题。本文将探讨内存泄露的定义、危害、检测方法及解决策略,帮助你掌握这一关键知识点。通过学习如何正确管理内存、使用智能指针和RAII原则,避免内存泄露,提升代码健壮性。同时,了解常见的内存泄露场景,如忘记释放内存、异常处理不当等,确保在面试中不被秒杀。最后,预祝大家新的一年工作顺利,涨薪多多!关注威哥爱编程,一起成为更好的程序员。
533 0
|
存储 缓存 C语言
【c++】动态内存管理
本文介绍了C++中动态内存管理的新方式——`new`和`delete`操作符,详细探讨了它们的使用方法及与C语言中`malloc`/`free`的区别。文章首先回顾了C语言中的动态内存管理,接着通过代码实例展示了`new`和`delete`的基本用法,包括对内置类型和自定义类型的动态内存分配与释放。此外,文章还深入解析了`operator new`和`operator delete`的底层实现,以及定位new表达式的应用,最后总结了`malloc`/`free`与`new`/`delete`的主要差异。
229 3