当前位置: 首页 > 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…...

联邦学习带宽资源分配

带宽资源分配是指在网络中如何合理分配有限的带宽资源&#xff0c;以满足各个通信任务和用户的需求&#xff0c;尤其是在多用户共享带宽的情况下&#xff0c;如何确保各个设备或用户的通信需求得到高效且公平的满足。带宽是网络中的一个重要资源&#xff0c;通常指的是单位时间…...

信息系统分析与设计复习

2024试卷 单选题&#xff08;20&#xff09; 1、在一个聊天系统(类似ChatGPT)中&#xff0c;属于控制类的是&#xff08;&#xff09;。 A. 话语者类 B.聊天文字输入界面类 C. 聊天主题辨别类 D. 聊天历史类 ​解析 B-C-E备选架构中分析类分为边界类、控制类和实体类。 边界…...

生成对抗网络(GAN)损失函数解读

GAN损失函数的形式&#xff1a; 以下是对每个部分的解读&#xff1a; 1. ⁡, ​ &#xff1a;这个部分表示生成器&#xff08;Generator&#xff09;G的目标是最小化损失函数。 &#xff1a;判别器&#xff08;Discriminator&#xff09;D的目标是最大化损失函数。 GAN的训…...

Docker 镜像上传到 AWS ECR:从构建到推送的全流程

一、在 EC2 实例中安装 Docker&#xff08;适用于 Amazon Linux 2&#xff09; 步骤 1&#xff1a;连接到 EC2 实例 ssh -i your-key.pem ec2-useryour-ec2-public-ip步骤 2&#xff1a;安装 Docker sudo yum update -y sudo amazon-linux-extras enable docker sudo yum in…...

DeepSeek11-Ollama + Open WebUI 搭建本地 RAG 知识库全流程指南

&#x1f6e0;️ Ollama Open WebUI 搭建本地 RAG 知识库全流程指南 &#x1f4bb; 一、环境准备 # 1. 安装 Docker 和 Docker Compose sudo apt update && sudo apt install docker.io docker-compose -y# 2. 添加用户到 docker 组&#xff08;避免 sudo 权限&…...

KKCMS部署

目录 账号 网站目录 快看CMS使用手册 http://10.141.19.241/kkcms/install/ 常规思路&#xff1a;页面点点观察url变化&#xff0c;参数 常规思路&#xff1a;点一个功能模块抓包看什么东西&#xff0c;正确是什么样&#xff0c;错误的是什么样&#xff0c;构造参数。 账号…...

时间序列预测的机器学习方法:从基础到实战

时间序列预测是机器学习中一个重要且实用的领域&#xff0c;广泛应用于金融、气象、销售预测、资源规划等多个行业。本文将全面介绍时间序列预测的基本概念、常用方法&#xff0c;并通过Python代码示例展示如何构建和评估时间序列预测模型。 1. 时间序列预测概述 时间序列是按…...

Github 2025-06-07 Rust开源项目日报Top10

根据Github Trendings的统计,今日(2025-06-07统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10Dart项目1TypeScript项目1RustDesk: 用Rust编写的开源远程桌面软件 创建周期:1218 天开发语言:Rust, Dart协议类型:GNU Affero Ge…...

黑马Javaweb Request和Response

一.介绍 在 Web 开发中&#xff0c;HttpServletRequest 和 HttpServletResponse 是两个非常重要的类&#xff0c;它们分别用于处理客户端的请求和服务器的响应。以下是它们的详细说明和使用方法&#xff1a; 1. HttpServletRequest HttpServletRequest 是一个接口&#xff0…...

【JMeter】后置处理器 - 提取器

文章目录 概览边界提取器正则提取器JSON提取器 概览 CSS/JQuery提取器&#xff1b;给网页使用JSON提取器&#xff1a;给JSON数据使用★边界提取器&#xff1a;给字符串使用★正则表达式提取器&#xff1a;更加高级的字符使用★Xpath提取器&#xff1a;给网页使用 边界提取器…...