当前位置: 首页 > news >正文

c++—内存管理、智能指针、内存池

1. 内存分析诊断工具:valgrind;

2. 内存管理的两种方式:

        ①用户管理:自己申请的,自己用,自己回收;效率高,但容易导致内存泄漏;

        ②系统管理:系统自动回收垃圾;安全性高,但消耗内存资源;

3. 内存分配的两种方式:

(1)静态分配(数组),存在于栈空间;

        ①优点:物理地址连续,方便遍历;

        ②缺点:分配与利用效率较低;

(2)动态分配(malloc、new),存在于堆空间;

        ①优点:使用效率较高;

        ②缺点:物理地址不连续;

4. 防止内存泄漏的方法:

        ①养成良好的编码规范;

        ②使用指针时,初始化就置空,避免野指针;

        ③malloc后及时free;new后及时delete;

        ④利用内存检测工具,如valgrind进行辅助处理;且可以利用g++选项工具同步分析;

5. 为什么c++没有GC机制?

        ①没有共同的基类:c++从C语言演变而来,可以直接操作指针,且类型之间可以相互转换,对于一个指针无法直到它实际指向类型;

        ②系统开销比较大:垃圾回收带来的系统开销,需要占用更多的内存,违反了c++的设计哲学“不为不必要的功能支付代价”,不符合高效特性;

        ③且c++中有析构函数实现智能指针,通过引用计数来管理资源的释放,对GC的需求不迫切;

6. 智能指针

    (1)智能指针的作用:帮助开发者对动态分配的对象进行声明周期管理,可以有效地防止内存泄漏;

    (2)分类,可以分为三类

        ①unique_ptr:独占指针

        ②shared_ptr:共享指针

        ③weak_ptr:弱指针

    (3)shared_ptr:共享指针

        ①共享:多个指针可以同时指向同一个对象,当最后一个指针被销毁或者指向其他对象时,这个对象会被释放;

        ②工作原理:内部有计数器,实时记录该共同空间被几个智能指针指向;其本质是对裸指针进行分装,下有封装例子;

        ③导致引用计数增加的情况:用一个智能指针初始化另一个智能指针、函数传参(传递一个智能指针,即复制),函数返回值(返回一个智能指针);

        ④引用计数减少的情况:给智能指针赋予新值指向一个新的对象、局部的智能指针离开作用域;

        ⑤语法:(注意:初始化不可以用 “ = ” 号),有两种初始化的方法(手动初始化、函数初始化std::make_shared函数)

shared_ptr<int>pi(new int(5));  //(初始化1)内部调用的构造函数
shared_ptr<int>pi = new int(5); //错误用法!
auto p = std::make_shared<string>("hello world");  //(初始化2)函数方法
int *p = pi.get();  //获得pi的裸指针,注意智能指针一旦释放,裸指针也就失效;
pi.reset();  //将pi置空;
pi.use_count();  //返回该智能指针的引用计数;
pi.reset(new int (6)); //改变pi的指向;
delete p;  //释放;
delete p;  //释放数组指针;void test(shared_ptr<int>&p)  //智能指针作为形参
{}reinterpret_pointer_cast<>();  //可以将任意类型的指针进行转换;

        ⑥自定义删除器,一些情况下,默认删除器处理不了(shared_ptr管理动态数组),需要自己指定删除器,下有详细例子;

        ⑧指针类型转换函数

static_pointer_cast  //void*与裸指针转换
dynamic_pointer_cast //向下类型转型(基类→派生类),基类需要有虚函数;
const_pointer_cast   //去除裸指针的const属性;
reinterpret_pointer_cast //任意类型之间裸指针转换;

    (4)unique_ptr:独占指针

        ①同一时刻,只能有一个unique_ptr指向这个对象,当指针销毁,指向的对象也销毁;

        ②语法,(注意:初始化不可以用 “ = ” 号),有两种初始化的方法(手动初始化、函数初始化std::make_unique函数)

unique_ptr<int>p(new int(5));
unique_ptr<int>p = new int(5);  //错误用法:不可以使用=
atuo pi = std::make_unique<string>("hello world");

        ③其他操作方法例如reset()、get()等于shared_ptr一样;

    (5)weak_ptr:独占指针

        ①weak_ptr是弱指针,不是独立的指针,不能单独操作所指向的资源;

        ②用处一:weak_ptr辅助shared_ptr的使用(监视shared_ptr 指向对象的生命周期);

        ③用处二:weak_ptr和shared_ptr之间可以相互转换,shared_ptr可以赋给weak_ptr,反过来不可以;

      (6)自己封装的智能指针shared_ptr<>();

hpp:

#pragma once
#include <iostream>
using namespace std;
//自己封装的智能指针shared_ptr<>();
template <typename T>
class Smartpointer
{
public:template <typename U>friend class Smartpointer;  //声明一种友元类Smartpointer() : m_p(nullptr){//m_p = nullptr;m_count = new long(0);}explicit Smartpointer(T * p)  //禁止隐式转换,就是不可以使用=,只能使用()初始化{cout<<"explicit"<<endl;if(p != nullptr){m_p = p;m_count = new long(1);  //次数计为1}else{m_p = nullptr;m_count = new long(0);  //次数为0}}template <typename U>Smartpointer(T *p, Smartpointer<U> &other)  //另外一种类型U?{if(p != nullptr){m_p = other.m_p;m_count = other.m_count;(*m_count)++;}else{m_p = nullptr;m_count = other.m_count;}}Smartpointer(Smartpointer<T> &other)  //拷贝构造{cout<<"拷贝构造"<<endl;if(other.m_p != nullptr){m_p = other.m_p;m_count = other.m_count;(*m_count)++;}else{m_p = nullptr;m_count = other.m_count;}}Smartpointer<T> & operator=(const Smartpointer<T> &other)  //=重载{cout<<"operator="<<endl;if(other.m_p != nullptr){m_p = other.m_p;m_count = other.m_count;(*m_count)++;}else{m_p = other.m_p;m_count = other.m_count;}return *this;}Smartpointer(Smartpointer<T>&&other)  //移动构造{cout<<"移动构造"<<endl;if(other.m_p = nullptr){m_p = other.m_p;other.m_p = nullptr;m_count = other.m_count;other.m_count = nullptr;}else{m_p = nullptr;m_count = other.m_count;}}~Smartpointer()  //析构函数{if((m_p != nullptr) && (--(*m_count) == 0)){cout<<"~Smartpointer"<<endl;delete m_p;delete m_count;}else{m_p = nullptr;m_count = nullptr;}}long use_count() const  //函数后面加const的作用?{return *m_count;}T * get()  //返回裸指针{return m_p;}void reset(T *p){if(p = nullptr){m_p = p;(*m_count)--;m_count = new long(1);  //引用计数从新置为1}else{m_p = nullptr;m_count = new long(0);}}void reset(){m_p = nullptr;(*m_count)--;}void swap(Smartpointer<T> &other){std::swap(m_p,other.m_p);  //c库内置函数实现交换std::swap(m_count,other.m_count);}T operator*(){ cout<<"operator*"<<endl;return *m_p;}T * operator->(){return m_p;}operator bool(){return m_p != nullptr;}T operator[](int index)  //重载[]{return m_p[index];}template <typename T1, typename U1>friend Smartpointer<T1> static_pointer_cast(Smartpointer<U1>&other);  //声明一种友元函数,用于不同类型的智能指针转换private:T * m_p;  //裸指针long * m_count;  //引用计数指针
};template <typename T, typename U>
Smartpointer<T> static_pointer_cast(Smartpointer<U>&other)
{T * temp = static_cast<T *>(other.m_p);return Smartpointer(temp,other);
}

cpp:

#include "smart_pointer.hpp"
#include <iostream>
#include <string>using namespace std;int main(int argc, char **argv)
{Smartpointer<int>t1(new int (5));cout<<(*t1)<<endl;cout<<t1.use_count()<<endl;Smartpointer<int>t2(t1);cout<<t2.use_count()<<endl;cout<<t1.use_count()<<endl;Smartpointer<string>t3(new string ("hello world"));// Smartpointer<string>t2(t4,t3);//Smartpointer<int> static_pointer_cast(t3);  //指针类型转换没有成功?Smartpointer<int>t4 = t2;cout<<(*t4)<<endl;cout<<t4.use_count()<<endl;Smartpointer<int>t5(std::move(t4));return 0;
}

7. 内存池

    (1)new内存分配细节

        ①new分配内存实际是调用malloc函数进行内存分配的;

        ②malloc实际分配内存时,不单单分配需要的内存大小,还要附加大量的附带内存,用以记录相关使用信息,包括记录分配了多少个字节(占4字节)、调试信息(占30-60字节)、边界调整(占10字节)、尾信息(4字节),也就是说除了实际分配的内存(比如给一个int变量分配4字节),还要附加70字节左右的附加内存,内存浪费很严重;尤其是频繁申请小块内存时,浪费更加严重;

        ③重载new操作符、重载delete操作符

void *operator new(size_t size)
{int *p = (int *)malloc(sizeof(int)):return *p;    
}void *operator new[](size_t size)
{void *p = malloc(size);  //内部会有转换机制,将你输入的个数,乘以类型的单位字节,算出来总数字节赋给size;return p;
}void *operator delete[](void *p)
{free(p);
}void *operator delete(void *p)
{free(p);
}

        ④定位new(pleacement new)

        在已经分配的原始内存中初始化一个对象,相当于从之前已经分配好的大块内存中取出一块来给新的变量使用;通常应用①在硬件设备地址与c++的类直接关联;②容器也利用了预分配内存,然后逐步使用的方法;

void *p1 = (void*)new char[sizeof((A))];
A *p2 = new (p1)A();  //调用了无参构造函数,使用的是原来p1的大块内存;//自定义有参的话,就可以使用A(12)带参数了;

    (2)内存池(池化技术是解决内存开销问题的,像线程池、内存池,其内部的机理是利用链表形成大内存,后面每次使用时,都分配一个结点空间给变量使用)

        ①作用:减少malloc次数,就减少了对内存的浪费;

        ②原理:用malloc分配一大块内存,当后面使用要分配时,从这一大块内存中一点一点分派,当一大块内存快用完时,再用malloc申请一大块内存,然后再一点一点分配;

        ③嵌入式指针,是借用A对象所占用的前8个字节(可能是2个整型数等),来充当指针,当被分配时,就指针后移,将该部分空间分配给新变量,利用内存共享,实现了空间的高效利用;

        内存池的代码实现:

#include <iostream>using namespace std;class Test
{
public:Test() = default;Test(int num){m_num = num;}void * operator new(size_t size){cout<<"size = "<<size<<endl;Test *temp;if(m_head == nullptr){cout<<"malloc"<<endl;m_head = (Test *)malloc(sizeof(Test) * 50);temp = m_head;for(int i = 0; i < 50; i++){temp->next = temp + 1;temp = temp->next;}temp->next = nullptr;}cout<<"mem"<<endl;temp = m_head;m_head = m_head->next;return m_head;}void * operator new[](size_t size){cout<<"new[] "<<size<<endl;void *p = malloc(size);  //这里的size会自动转换为以字节为单位的大小return p;}void operator delete(void *p){Test * temp = (Test *)p;temp->next = m_head;m_head = temp;}void operator delete[](void *p){cout<<"delete[]"<<endl;free(p);}int m_t;int m_num;Test *next;static Test *m_head;
};Test * Test::m_head = nullptr;int main(int argc, char **argv)
{Test *p1 = new Test[10];  //这里的10指的是10个Test大小的内存delete [] p1;cout<<"begin:"<<endl;Test *p2 = new Test(2); //??这里是重载new,为什么当做构造函数报错?,因为Test(2)先构造一个对象,就像int(5)先初始化一个值为5的变量Test *p3 = new Test();   //为什么已添加这个就报错?p3->m_num = 3;p3->m_t = 4;cout<<p3->m_num<<" : "<<p3->m_t<<endl;return 0;
}

相关文章:

c++—内存管理、智能指针、内存池

1. 内存分析诊断工具&#xff1a;valgrind&#xff1b; 2. 内存管理的两种方式&#xff1a; ①用户管理&#xff1a;自己申请的&#xff0c;自己用&#xff0c;自己回收&#xff1b;效率高&#xff0c;但容易导致内存泄漏&#xff1b; ②系统管理&#xff1a;系统自动回收垃圾…...

JAVA使用HTTP代码示例

以下是使用Java发送HTTP请求的示例代码&#xff1a; java import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; public class HttpExample { public static void main(String[] args) { try { …...

【网络协议详解】——电子邮件系统协议(学习笔记)

目录 &#x1f552; 1. 电子邮件系统概述&#x1f552; 2. 简单邮件传送协议SMTP&#x1f552; 3. SMTP协议的命令和响应&#x1f558; 3.1 命令&#x1f564; 3.1.1 HELO&#x1f564; 3.1.2 MAIL FROM&#x1f564; 3.1.3 RCPT TO&#x1f564; 3.1.4 DATA&#x1f564; 3.1.…...

年度发布 | MeterSphere一站式开源持续测试平台发布v2.10 LTS版本

2023年5月25日&#xff0c;MeterSphere一站式开源持续测试平台正式发布v2.10 LTS版本。这是继2022年5月发布v1.20 LTS版本后&#xff0c;MeterSphere开源项目发布的第三个LTS&#xff08;Long Term Support&#xff09;版本。MeterSphere开源项目组将对MeterSphere v2.10 LTS版…...

从 OceanBase 迁移数据到 DolphinDB

OceanBase 是一款金融级分布式关系数据库&#xff0c;具有数据强一致、高可用、高性能、在线扩展、高度兼容 SQL标准和主流关系数据库、低成本等特点&#xff0c;但是其学习成本较高&#xff0c;且缺乏金融计算函数以及流式增量计算的功能。 DolphinDB 是一款国产的高性能分布…...

淘宝商品列表数据接口(支持价格、销量排序)

淘宝商品列表数据接口是淘宝提供的一种可以获取淘宝商品信息的接口。通过该接口&#xff0c;可以获取到具有一定规则的商品信息&#xff0c;例如按照价格排序、按照销量排序等。接口返回的数据格式为JSON格式&#xff0c;可以方便地处理数据。 我们可以通过调用淘宝提供的API&…...

Android 11 版本变更总览

Android 11 版本 Android 11 总览重大隐私权变更行为变更&#xff1a;所有应用行为变更&#xff1a;以 Android 11 为目标平台的应用功能和 API 概览Intent系统广播 intent&#xff08;API 级别 30&#xff09;通用应用 intent&#xff08;API 级别 30&#xff09; Android 11 …...

传染病学模型 | Matlab实现基于SIS传染病模型模拟城市内人口的互相感染及城市人口流动所造成的传染

文章目录 效果一览基本描述模型介绍程序设计参考资料效果一览 基本描述 传染病学模型 | Matlab实现基于SIS传染病模型模拟城市内人口的互相感染及城市人口流动所造成的传染 模型介绍 SIS模型是一种基本的传染病学模型,用于描述一个人群中某种传染病的传播情况。SIS模型假设每个…...

物联网技术如何改变我们的生活:一位资深物联网专家的见解

物联网&#xff08;IoT&#xff09;是指通过网络互联的物理设备、车辆、建筑物以及其他物品&#xff0c;这些物品都内置了传感器、执行器、软件和网络连接器&#xff0c;使它们能够收集和交换数据。物联网技术已经在各个领域产生了深远的影响&#xff0c;包括家庭、医疗、交通、…...

node.js+vue.js大学生在线选课系统的设计与实现93pul

本次设计任务是要设计一个选课系统的设计与实现&#xff0c;通过这个系统能够满足用户对选课信息的需求。系统的主要功能包括&#xff1a;个人中心、学生管理、教师管理、选课信息管理等功能。 管理员可以根据系统给定的账号进行登录&#xff0c;登录后可以进入选课系统的设计与…...

华为OD机试真题 Java 实现【寻找符合要求的最长子串】【2023Q1 200分】

一、题目描述 给定一个字符串 s ,找出这样一个子串: 该子串中的任意一个字符最多出现2次;该子串不包含指定某个字符;请你找出满足该条件的最长子串的长度。 二、输入描述 第一行为要求不包含的指定字符,为单个字符,取值范围[0-9a-zA-Z]。 第二行为字符串s,每个字符范…...

接口测试工具Postman接口测试图文教程

目录 一、前言 二、Postman安装和使用 三、请求方式 四、资金记录接口实例演示 一、前言 在前后端分离开发时&#xff0c;后端工作人员完成系统接口开发后&#xff0c;需要与前端人员对接&#xff0c;测试调试接口&#xff0c;验证接口的正确性可用性。而这要求前端开发进…...

视频编辑软件:迅捷视频工具箱

这是一款功能强大、易于使用的视频编辑工具&#xff0c;支持视频剪辑、视频转换、音频转换、视频压缩、视频水印、字幕贴图等实用功能&#xff0c;可以帮助你制作出高质量的视频作品。&#xff08;传送门&#xff1a;https://www.xunjiepdf.com/xjspgjx&#xff09; 功能简介 …...

网络知识点之-HTTP协议

超文本传输协议&#xff08;Hyper Text Transfer Protocol&#xff0c;HTTP&#xff09;是一个简单的请求-响应协议&#xff0c;它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII形式给出&#xff1b;而消息内…...

K类函数和KL类函数

Class K \mathcal{K} K function- K \mathcal{K} K类函数 Definition: A continuous function α : [ 0 , a ) → [ 0 , ∞ ) \alpha:[0,a)\rightarrow[0,\infin) α:[0,a)→[0,∞) is said belong to class K \mathcal{K} K if it strictly increasing and α ( 0 ) 0 …...

华为OD机试之完美走位(Java源码)

完美走位 题目描述 在第一人称射击游戏中&#xff0c;玩家通过键盘的A、S、D、W四个按键控制游戏人物分别向左、向后、向右、向前进行移动&#xff0c;从而完成走位。 假设玩家每按动一次键盘&#xff0c;游戏任务会向某个方向移动一步&#xff0c;如果玩家在操作一定次数的键…...

Vue 原始(传统)或特别的视频组件具体实现方法

一、原始的播放器组件&#xff08;传统的视频播放组件&#xff09; 参考链接 1. Vue2视频播放&#xff08;Video&#xff09; 二、自定义视频播放组件&#xff0c;自播放&#xff0c;无控制模式 简单点的理解&#xff0c;就是没有点击就会暂停播放视频&#xff0c;还有忽略…...

香豆素荧光标记652966-03-5,ATTO425 acid,ATTO 425 羧酸,进行简析说明

中文名称&#xff1a;ATTO 425 羧酸 英文名称&#xff1a;ATTO425 COOH&#xff0c;ATTO-425 carboxylic acid 规格标准&#xff1a;10mg&#xff0c;25mg&#xff0c;50mg CAS&#xff1a;652966-03-5 分子式&#xff1a;C22H27NO6 分子量&#xff1a;401.46结构式&#xff1a…...

linux信号量与PV操作知识点总结

信号量 信号量(semaphore) 与已经介绍过的 IPC 结构不同&#xff0c;它是一个计数器&#xff0c;信号量用于实现进程间的与斥与同步&#xff0c;而不是用于存储进程间通信数据。 1、特点 &#xff08;1&#xff09;信号量用于进程间同步&#xff0c;若要在进程间传递数据需要结…...

6-python中的string类型

目录 内容提要字符串截取python的转义字符 \python的字符串格式化format()的参数format()的数字格式化 字符串常用函数count()函数endwith()函数 与 startwith()函数find()函数与index()函数find()函数 ⭐index()函数 判断字符串内的字符种类函数isalnum()函数isalpha()函数isd…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

iview框架主题色的应用

1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题&#xff0c;无需引入&#xff0c;直接可…...