首页 > 系统相关 >C++内存管理

C++内存管理

时间:2024-02-21 21:11:31浏览次数:27  
标签:10 管理 int C++ 内存 new 分配 delete

C++内存管理

目录

内存模型

内存类型 作用 生命周期
常量存储区 存放常量,不允许修改
全局/静态存储区 全局变量和静态 static对象、类static数据成员 由编译器自动创建和销毁,static对象在使用之前分配,在程序结束时销毁。
自由存储区 malloc分配的内存块,free 释放
函数内局部变量 函数执行结束时这些存储单元自动被释放。
用来动态分配的内存,由new创建分配,delete释放 动态对象的生命周期由应用程序来控制,也就是说,当动态对象不再使用时,我们的代码必须显示地销毁他们。

堆与栈的区别

管理方式不同;
	- 栈:有系统、编译器自动分配
	- 堆:需要程序员自己申请,程序员释放,容易内存泄露

空间大小不同;
	对于32位系统而言
    - 栈:最大只有2M
    - 堆:最大可以到4GB,没有大小限制
	
分配效率不同;
	- 栈:由系统分配,速度较快,程序员无法控制
    - 堆:速度慢,容易产生内存碎片

生长方向不同;
    - 栈:生长方向向下,内存地址减小
    - 堆:生长方向向上,内存地址增加

分配方式不同;
    - 栈:栈有2种分配方式:静态分配和动态分配
    - 堆:都是动态分配的,没有静态分配的堆。
   
能否产生碎片不同;
	- 栈:栈是先进后出的队列
	- 堆:频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片

其他说明

栈:从高地址往低地址增长,存放的是非静态局部变量、函数参数以及返回值等具有临时性的值;动态内存的维护都是要用指针保存地址的,栈就是保存指针的地方,因此栈的容量很小,比如VS编译器给栈分配的大小是1M,一些LInux中能达到8M;栈是系统自动维护的。

内存映射段:装载共享动态内存库,用户可使用系统接口创建共享内存,用作进程间通信,是高效的I/O映射方式。这一部分后续会学习;

堆:从低地址往高地址增长,用于程序运行时动态内存的分配,栈存放的指针维护的空间就在堆,所以堆占的空间比较大,一般有几个G,需要用户自己维护;

数据段:存放着全局数据和静态数据,这部分和栈对应,是存放着具有常性的值;

代码段:可执行的代码、只读常量。

new和delete

C++提出了新的内存管理方式:定义新的操作符new和delete进行动态内存管理。

// 动态申请一个int类型的空间
int* ptr1 = new int;

// 动态申请一个int类型的空间并初始化为10
int* ptr2 = new int(10);

// 动态申请10个int类型的空间
int* ptr3 = new int[10];

delete ptr1;
delete ptr2;
delete[] ptr3;

解释:

ptr1: 指向的是一个动态内存分配的、未初始化的int类型对象;

ptr2: 指向的是一个值为10,类型是int的对象;

ptr3: 指向的是一个大小为10个int,也就是40(32位)个字节、未初始化的对象;

delete:如果有申请指定大小的空间,需要使用[]。

#include <iostream>
using namespace std;


class MyClass
{
    public:
       MyClass():i(2){}                           // 无参 初始化
       MyClass(int a):i(a){}                      // 有参 初始化
       virtual void foo(){ cout<<i<<endl;}        // 
       int i;
};

int main()
{
	MyClass *p1 = new MyClass;
    p1->foo();
    MyClass *p2 = new MyClass(10);  
    p2->foo();    
    MyClass *p3 = new MyClass[5];         // 创建 5个MyClass对象,同时默认赋值
    //MyClass *p4 = new MyClass[5](20);   // 错误写法
    p3->foo();
    delete p1;
    delete p2;
    delete[] p3;
   
    return 0;
}

// -----------------------------------------------------------------------
2
10
2
6855584
200

malloc/free和new/delete区别

  • new关键字是C++的一部分是操作符,malloc是由C库提供的函数
  • new以具体类型为单位进行内存分配,malloc以字节为单位进行内存分配,需要手动计算空间大小并传递
  • new在申请单个类型变量时可进行初始化。malloc不具备内存初始化的特性
  • new返回的是空间的类型,malloc的返回值为void*, 在使用时必须强转,new不需要
  • new 申请失败需要捕获异常,malloc申请空间失败时,返回的是NULL

从底层来看 malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理

new运算符的原理

1.内存分配
  调用相应的  operator new(size_t) 函数,动态分配内存。如果 operator new(size_t) 不能成功获得内存,则调用 new_handler()函数用于处理new失败问题。如果没有设置 new_handler() 函数或者 new_handler() 未能分配足够内存,则抛出 std::bad_alloc 异常

2.构造函数
  在分配到的动态内存块上 初始化相应类型的对象(构造函数)并返回其首地址。如果调用构造函数初始化对象时抛出异常,则自动调用 operator delete(void*, void*) 函数释放已经分配到的内存。

3.返回指针

new/delete的使用要点

new内置了sizeof、类型转换和类型安全检查功能。

对于非内部数据类型的对象而言,new在创建动态对象的同时完成了初始化工作。

如果对象有多个构造函数,那么new的语句也可以有多种形式

#include <iostream>
using namespace std;

class Obj
{
public:
    Obj(){}                     // 无参数的构造函数
    Obj(int x):objx(x){}        // 带一个参数的构造函数
    int objx;
};

void Test(void)
{
  Obj *a = new Obj;				//无参数,构造初始化
  cout << a->objx << endl;      // 随机初始化
  Obj *b = new Obj(200);        // 含参,构造初始化
  cout << b->objx << endl;      // 初值为200
  Obj *objects = new Obj[100];  // 创建100个动态对象
  delete a; 
  delete b;
  delete []objects;   // 正确的用法
}
int main(){
	Test();
    return 0;
}

判断内存申请成功

如果在申请动态内存时找不到足够大的内存块,内存耗尽问题

判断指针是否为NULL

void Func(void){ 
	A *a = new A; 
	if(a == NULL) {  return; } 
}

delete与delete[]区别

delete只会调用一次析构函数,而delete[] 会调用每一个成员的析构函数。

在More Effective C++中有更为详细的解释:

“当delete操作符用于数组时,它为每个数组元素调用析构函数,然后调用operator delete来释放内存。”

delete与new配套,delete []与new []配套

  • 调用析构函数

  • 释放内存空间

int* a = new int(10);
int * arr = new int[10];
//相当域创建了地址, 必须需要通过指针进行接收
for (int i = 0; i < 10; i++){
    arr[i] = i + 100;
}
for (int i = 0; i < 10; i++){
    cout << arr[i] << endl;
}
delete [] arr;

参考资料

https://juejin.cn/post/7306814408595603506

C++ 动态内存分配(new,delete)

C++ 内存管理(建议收藏)

标签:10,管理,int,C++,内存,new,分配,delete
From: https://www.cnblogs.com/tian777/p/18026226

相关文章

  • C++智能指针
    C++智能指针目录C++智能指针unique_ptr简单示例构造方法释放和重置shared_ptr构造方法常用函数构造重置和析构获得原始指针注意事项weak_ptr构造方法常用函数解决循环引用参考资料在C++中,内存的分配和释放都是由开发者手动实现的。这种方式虽然很灵活,但也十分容易出错,比如忘记释......
  • C++ 第一节课 名字空间 ,输入输出函数,和 C 语言的区别
    #include<iostream>//#include头文件,C++标准库的头文件都不带.h(.h是C库头文件添加的)#include<cstdio>#include<cstring>usingnamespacestd;//namespace命名空间为了防止变量名字冲突//命名空间中定义自己的变量或函数或类,都是独立的//所有的命名空......
  • 49. 字母异位词分组c++
    刷力扣还有点不太习惯,主要是C++只学了皮毛。看了官方活用map就是好啊。把字母都排好序然后判断就好了。map<string,vector<string>>m;for(inti=0;i<strs.size();i++){stringtem=strs[i];sort(tem.begin(),tem.end());......
  • 导包和包管理
    目录一、什么是包二、main函数和main包三、包管理1.main包2.创建自定义包3.导包四、init函数和包的初始化1.实例-验证包的初始化顺序(1)修改rectprops.go(2)修改geometry.go(3)运行结果(4)再修改geometry.go五、实现导包而不用1.错误导包2.错误屏蔽器3.空白标识符避错一、什么......
  • 【C++】编写一个具有老式风格接口的函数,其原型如下:int reduce(long arr[], int n)。实
    #include<iostream>#include<string>usingnamespacestd;intreduce(longarr[],intn){sort(arr,arr+n);autostr=unique(arr,arr+n);returnstr-arr;}intmain(){longarr[10]={15,8,5,6,11,11,6,6,198,50};......
  • c++类开发的第三篇(讲明白友元函数和this指针)
    friend_function成员变量和函数的存储c++实现了封装,数据和处理数据的操作(函数)是分开存储的。c++中的非静态数据成员直接内含在类对象中,就像c语言的struct一样。成员函数并不会出现在对象中,而是作为类的一部分存储在代码段中,需要通过对象或对象指针进行调用。成员函数可......
  • 操作系统实训_基于多级目录的文件管理系统
    title:操作系统实训_基于多级目录的文件管理系统author:fxydate:2022-07-0719:18:00tags:实训category:实训readmore:truedescription:SDUT操作系统实训,基于多级目录的文件管理系统,c++1、实训报告:github实训报告2、代码://基于多级文件目录的文件管理系统#includ......
  • C++开发基础知识(修改)
    2024-01-0820:13星期一博客内容来自相关书籍和网站内容总结,仅供个人参考使用:笔者@StuBoo使用目录快速转到技术面试问题汇总、算法笔记1.C++语言基础1.1语言特性面向对象编程(OOP):C++支持面向对象编程,包括封装、继承和多态。通过类和对象,可以将数据和方法组织成单个单元,......
  • Java人力资源管理系统源码(含数据库)-springboot+vue+mysql
    EHR人力资源管理系统是一种利用现代技术,如云计算、大数据等,来实现企业人力资源信息电子化、流程自动化的系统。它覆盖了人力资源管理的各个方面,从招聘、考勤、绩效到薪酬、社保公积金等,为企业提供一站式的解决方案。​1.招聘管理:-职位发布:系统支持在线发布职位信息,吸引候选人......
  • c++ 2 字母异位词
    //字母异位词是由重新排列源单词的所有字母得到的一个新单词。//示例1:////输入:strs=["eat","tea","tan","ate","nat","bat"]//输出:[["bat"],["nat","tan"],["ate","eat",&q......