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

【c++篇】:从基础到实践--c++内存管理技巧与模版编程基础

✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨
✨个人主页:余辉zmh–CSDN博客
✨ 文章所属专栏:c++篇–CSDN博客

在这里插入图片描述

文章目录

  • 前言
  • 一.c/c++内存分布
  • 二.c/c++的动态内存管理方式
    • 2.1.c语言的动态内存管理方式
    • 2.2.c++的动态内存管理方式
    • 2.3.c/c++动态内存管理方式的区别
  • 三.new和delete的底层实现原理
    • 3.1`operator new`和`operator delete`函数
    • 3.2`new `和`delete`的实现原理
  • 四.定位new表达式
  • 五.内存泄漏
  • 六.模版初阶
    • 6.1泛型编程
    • 6.2函数模版
    • 6.3类模版

前言

内存管理和模板是C++编程中两个重要的主题,它们共同构成了高效、灵活和可复用的代码基础。内存管理涉及到如何有效利用计算机内存资源,确保程序的性能和稳定性;而模板则提供了一种参数化类型和函数的机制,使得代码能够以类型无关的方式编写,从而实现高度的抽象和复用。理解这些概念对于编写高质量和可维护的C++代码至关重要。本文将探讨C++中的内存管理和模板的基础知识,帮助读者掌握这两个核心主题,为构建复杂系统打下坚实的基础。

一.c/c++内存分布

在一个程序中,对于各种不同的数据需要存储在不同的地方,比如:局部数据存储在栈区,静态数据和全局数据存储在静态区或者数据段,常量数据存储在常量区或代码段,动态申请的数据则是存储在堆上。

在c/c++中,内存分为以下几个区域:

  • 栈区:

    • 编译器自动分配和释放
    • 存放函数的局部变量,函数参数,返回地址等。
    • 具有先进后出的特性,栈是向下增长的。
    • 内存分配率高,但空间有限
  • 堆区:

    • 由程序员自己手动分配空间和释放,在C语言中由malloc,calloc,realloc等函数分配空间,而c++中使用new操作符。
    • 如果没有释放,程序结束时操作系统会回收,释放空间时,C语言使用free,而c++使用delete
    • 内存分配效率相对较低,但空间较大。
    • 堆是可以向上增长的。
  • 全局或静态区:

    • 存放全局变量和静态变量
    • 程序加载时分配内存空间,程序结束时释放。
  • 区或代码段:

    • 常量区存放常量等只读数据,防止修改数据。
    • 代码段存放程序的机器指令,只能读取,不能修改。

这里提供一段代码来分析一下数据的存储区域:

int globalVar =1;
static int staticGlobalVar=1;
void Test(){static int staticVar=1;int localVar=1;int num1[10]={1,2,3,4};char char2[]="abcd";const char*pChar3="abcd";int*ptr1=(int*)malloc(sizeof(int)*4);free(ptr1);
}

globalVar 全局变量 在数据段(静态区) staticGlobalVar 静态全局变量 在数据段(静态区)

staticVar 静态局部变量 在数据段(静态区) localVar 局部变量 在栈

num1局部数组 在栈

char2 字符数组 在栈 *char2 数组元素存储位置 在栈

pchar3 指针变量 在栈 *pchar3常量字符 在代码段(常量区)

ptr1指针变量 在栈 *ptr1 动态内存 在堆

二.c/c++的动态内存管理方式

2.1.c语言的动态内存管理方式

在C语言中申请动态内存主要通过malloc,calloc,realloc等函数,这些函数都是堆上申请空间,且都是void*类型,需要进行数据类型转换,在申请完之后还要进行判断是否为空(因为申请失败会返回空)。

  • malloc函数:在动态存储区申请申请一块指定大小的连续空间,返回空间的地址(数组返回的是首元素的地址),类型为void*类型。释放时使用free函数。

    int* p1=(int*) malloc(sizeof(int));
    free(p1);
    
  • calloc函数:在内存的动态存储区申请指定数量相同大小的内存空间,返回空间的地址(数组返回的是首元素的地址),类型为void*类型,和malloc不同的是,calloc会将申请成功的空间初始化为0。

    int *p2=(int*)calloc(3,sizeof(int));
    
  • realloc函数是对原来申请空间的扩充,也就是增加原来空间的大小,如果原先空间后面大小充足允许扩充,就会原地扩充,大小不足时,就会重新在其他地方申请空间,再将原本空间的数据拷贝过来,类型依然是void*类型。

    int* p3=(int*)realloc(p2,sizeof(int)*10);
    free(p3);
    

2.2.c++的动态内存管理方式

在c++中,动态内存分配主要通过new,delete两个关键字实现,相比于C语言的动态内存分配,c++的更为直观和方便。

  • new关键字用于动态申请内存空间,不需要显示内存空间大小(编译器会根据类型自己计算),返回的是申请空间的地址(对于数组来说,返回的是首元素的地址),也可以设置初始值来初始化申请的内存空间。

  • delete关键字1用于释放动态分配的内存空间,对于单个对象,使用delete释放,对于数组空间,需要在delete后加上[],表示释放整个数组空间。

    对于内置类型:

    • 动态申请一个int类型的未初始化空间:

      int* ptr1=new int;
      delete ptr1;
      
    • 动态申请一个int类型的空间并初始化为10:

      //初始化使用的是()
      int* ptr2=new int(10);
      delete ptr2;
      
    • 动态申请10个int类型的空间:

      //申请连续的空间时,使用的是[];
      int* ptr3=new int[10];
      delete[] ptr3;
      

    对于自定义类型:

    new会调用构造函数,delete会调用析构函数;而mallocfree不会

    class A {
    public:A(int a=0) :int _a(a){cout << "A()" << endl;}~A() {cout << "~A()" << endl;}
    private:int _a;
    };int main() {//new申请空间后调用构造函数完成初始化A* ptr1 = new A;//delete在释放空间前会调用析构函数完成对空间资源的清理delete ptr1;A* ptr2 = (A*)malloc(sizeof(A));if (ptr2 == NULL) {perror("malloc fail");}free(ptr2);return 0;
    }
    

    在这里插入图片描述

2.3.c/c++动态内存管理方式的区别

c语言使用的是mallocfree,而c++使用的是newdelete,他们的共同点是:都是从堆上申请内存空间,并且需要用户手动释放空间。而不同点是:

  • mallocfree是函数,而newdelete是操作符。
  • malloc申请的空间不会初始化,而new申请的空间可以初始化,初始化时使用new 类型(初始值)
  • malloc申请空间时需要手动计算空间大小并传递,而new只需在new后面加上类型就可以,如果申请多个对象时,使用new 类型[个数]
  • malloc的返回值为void*类型,并且需要强制转换类型,而new不需要,直接在new后面加上类型既可
  • malloc申请空间失败时返回NULL,所以需要判断空间是否申请成功,而new不需要判断,因为new是抛异常
  • 对于自定义类型对象,mallocfree只能开辟空间和释放,不会调用构造函数和析构函数,而new在申请空间后会调用构造函数完成初始化,delete在释放空间前会调用析构函数完成对空间中资源的清理

三.new和delete的底层实现原理

3.1operator newoperator delete函数

  • operator new是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,而operator new实际上也是通过malloc来申请空间,如果malloc申请空间成功就会直接返回,否则就会抛异常

  • operator new一样,operator delete也是系统提供的全局函数,delete在底层通过operator delete全局函数来释放空间,而operator delete最终也是通过调用free来释放空间

    下面代码通过模拟实现来演示new和delete如何完成空间的申请和释放:

    void* operator new(size_t size) {void* ptr = malloc(size);if (!ptr) {throw bad_alloc();}cout << "申请空间调用operator new函数:" << endl;cout << "void* operator new(size_t size)" <<" "<< ptr << endl;return ptr;
    }void operator delete(void* ptr) {cout << "释放空间调用operator delete函数:" << endl;cout << "void operator delete(void* ptr)" <<" "<< ptr << endl;free(ptr);
    }class Myclass {
    public:Myclass() {cout << "申请空间后调用构造函数完成初始化:" << endl;cout << "Myclass()" << endl;}~Myclass() {cout << "释放空间前调用析构函数完成对象资源的清理:" << endl;cout << "~Myclass()" << endl;}
    };int main() {Myclass* ptr = new Myclass;cout << " " << endl;delete ptr;return 0;
    }
    

    在这里插入图片描述

3.2new delete的实现原理

  • 对于内置类型:

    如果申请的是内置类型的空间,newmallocdeletefree基本类似,不同点可以看上面的2.3内容。

  • 对于自定义类型:

    • new的原理:

      1.调用operator new申请空间

      2.申请空间成功后调用构造函数完成初始化

    • new T[N]的原理:

      1.调用operator new[]函数,实际调用operator new函数完成对N个对象空间的申请

      2.申请N个空间,就要调用N次构造函数完成初始化

    • delete的原理:

      1.在释放空间前调用析构函数,完成对对象空间中资源的清理

      2.调用operator delete函数释放空间

    • delete []的原理:

      1.在释放空间前调用N次析构函数完成对N个对象的资源的清理

      2.调用operator delete[]函数释放空间,实际上是调用operator delete函数来释放空间

四.定位new表达式

在c++中,定位new表达式是一种特殊的语法结构,它允许程序员在自定义的内存位置上构造对象。定位new不会分配内存,他只会在指定的内存地址上调用对象的构造函数。使用定位new需要确保提供的内存位置足够大,否则可能会导致未定义行为。同样的,如果不再需要该对象时,需要手动调用析构函数来释放空间,因为定位new不会管理内存的生命周期。

以下面这段代码为例:

class Myclass {
public:Myclass(int a):_a(a){cout << "Myclass(int a)" << endl;}~Myclass() {cout << "Myclass()" << endl;}private:int _a;
};int main() {//分配一块足够大的内存char ptr[sizeof(Myclass)];//在ptr指向的内存上构造Myclass对象//使用定位new格式,new(内存空间)类类型(初始化值)Myclass* p = new(ptr)Myclass(12);//不再需要该对象时,手动调用析构函数p->~Myclass();return 0;
}

在这里插入图片描述

在上面这个例子中,ptr是一个字符数组,其大小足够容纳一个Myclass对象,然后使用定位newptr的内存空间上构造一个Myclass对象,最后在手动调用析构函数来销毁。

五.内存泄漏

内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

  • 内存泄漏的常见原因包括:

    • 程序员的错误:程序员未正确地释放动态内存,或者使用了不恰当的数据结构,导致内存无法释放。
    • 循环引用:在使用面向对象的编程语言时,两个或多个对象彼此引用,导致它们之间形成了循环引用,使得这些对象无法被垃圾回收器及时释放。
  • 内存泄漏的解决办法主要包括:

    • 正确使用动态内存分配:在使用完动态内存之后,及时将其释放。
    • 使用内存泄漏检测工具:可以自动检测出内存泄漏问题,并给出错误信息和定位。常见的内存泄漏检测工具包括Valgrind、GDB、DMalloc、Purify、Electric Fence等。

六.模版初阶

6.1泛型编程

我们首先来看一下下面这段代码:

void Swap(int& a,int&b){int tmp=a;a=b;b=tmp;
}
void Swap(double& a,double&b){double tmp=a;a=b;b=tmp;
}
void Swap(char& a,char&b){char tmp=a;a=b;b=tmp;
}

如果我们要写一个交换函数,对于不同类型的数据需要不同的类型函数,虽然可以使用函数重载来实现,但是复用率较低,而且有新的类型时,还需要自己增加对应类型的函数,并且可维护性较低,如果一个出错可能所有的重载函数均会出错。

那么能不能给编译器一个模版,让编译器自己根据类型来生成对应的代码呢?答案是当然可以,这就是我们接下来需要了解的泛型编程。

泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模版是泛型编程的基础。

模版分为函数模版和类模版

6.2函数模版

函数模版与类型无关,在使用时被参数化,可以根据使用类型产生对应类型的函数。

  • 函数模版格式:
//可以使用typename或者class来定义模版参数,但不能使用struct
template<typename/class T1,typename/class T2....>
返回值类型 函数名(参数列表){...
}

以上面的交换函数为例:

template<typename T>
void Swap(T& a, T& b) {T tmp = a;a = b;b = tmp;
}
  • 函数模版的实例化:

    用不同类型的参数使用函数模版时,称为函数模版的实例化,实例化分为:隐式实例化和显示实例化。

    • 隐式实例化:让编译器根据实参推演模版参数的实际类型

      template<typename T>
      void Swap(T& a, T& b) {T tmp = a;a = b;b = tmp;
      }
      int main() {int a = 1, b = 2;Swap(a, b);double c = 3, d = 4;Swap(c, d);cout << a <<" "<< b << endl;cout << c << " " << d << endl;return 0;
      }
      

      在这里插入图片描述

    • 显示实例化:在函数名前面指定模版参数的实际类型

      如果对于a,b两个不同类型的数据使用函数模版时,就会产生歧义

      template<typename T>
      T Add(const T& a, const T& b) {return a + b;
      }
      int main()
      {int a = 10;double b = 20.0;cout <<(Add(a, b))<< endl;return 0;
      }
      

      在这里插入图片描述

      此时有两种处理方式:

      1.用户自己强制转化

      Add(a,(int)b);
      

      2.使用显示实例化

      Add<int>(a,b);
      

      以上两种方式结果都为30:

      在这里插入图片描述

  • 函数模版的原理:

    在编译阶段,对于模版函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。

    在这里插入图片描述

6.3类模版

  • 类模版的定义格式:

    //使用的是class关键字
    template<class T1,class T2....>
    class 类模版名
    {//类中成员定义....
    }

    以栈Stack为例:

    template<class T>
    class Stack {
    public:Stack(int capacity=4):_a(new T[capacity]), _top(0), _capacity(capacity){cout << "Stack()" << endl;}//其他成员函数....//析构函数在类中声明,在类外定义~Stack();private:T* _a;int _top;int _capacity;
    };
    //在类外定义时需要加模版参数列表
    //函数名前加:(类名<T>::)
    template<class T>
    Stack<T>::~Stack() {cout << "Stack<T>::~Stack()" << endl;delete _a;_top = 0;_capacity = 0;
    }
    
  • 类模版的实例化:

    类模版实例化与函数模版实例化不同,类模版实例化需要再类模版名字后加<>,然后将实例化的类型放在<>中,类模版名字不是真正的类,而实例化的结果才是真正的类。

    以上面的栈模版为例:

    int main() {//Stack为类名,Stack<数据类型>才是类型Stack<int> s1(5);Stack<double> s2(10);Stack<char> s3(2);return 0;
    }
    

以上就是关于c++内存管理方式和模版初阶的讲解,如果哪里有错的话,可以在评论区指正,也欢迎大家一起讨论学习,如果对你的学习有帮助的话,点点赞关注支持一下吧!!!
在这里插入图片描述

相关文章:

【c++篇】:从基础到实践--c++内存管理技巧与模版编程基础

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;c篇–CSDN博客 文章目录 前言一.c/c内存分布二.c/c的动态内存管理方式2.1.c语言的动态内存管…...

如何减小 Maven 项目生成的 JAR 包体积 提升运维效率

在使用 Maven 构建 Java 项目时&#xff0c;有时需要减小生成的 JAR 包的体积&#xff0c;以提高部署效率或减少资源消耗。以下是一些有效的方法来减小 JAR 包的体积&#xff1a; 排除不必要的依赖打包时&#xff0c;依赖jar包独立于应用jar包 1. 排除不必要的依赖 通过排除项目…...

Python自动化会议记录与摘要生成

前言 在现代工作环境中&#xff0c;会议是团队沟通和决策的重要方式。然而&#xff0c;整理会议记录和生成摘要往往是一项耗时且容易出错的任务。幸运的是&#xff0c;借助Python编程语言以及一些强大的库&#xff0c;我们可以自动化这一过程&#xff0c;让机器帮助我们完成这…...

SwiftUI 中 List 或 Form 子视图关联的 swipeAction 导致展开动画异常的解决

问题现象 小伙伴们都知道,在 SwiftUI 中更快捷的增强 List 或 Form 子视图(Cell)交互功能的方法是使用 swipeAction 修改器。不过,对其使用稍有不慎也会横生枝节。 如上图所示,不适当的设置 Cell 视图布局会使 swipeAction 无法生成正确的收缩和展开动画。对此我们有什么…...

Apache Paimon Catalog

Paimon Catalog可以持久化元数据&#xff0c;当前支持两种类型的metastore&#xff1a; 文件系统&#xff08;默认&#xff09;&#xff1a;将元数据和表文件存储在文件系统中。hive&#xff1a;在 hive metastore中存储元数据。用户可以直接从 Hive 访问表。 2.2.1 文件系统…...

C++基础:三个字符串也能搞大小?

上一篇说了三个整数比较大小&#xff0c;按照顺序输入的&#xff0c;这次我们看看字符串的&#xff0c;顺便把那个简化以下&#xff1a; 题目:这次输入三个字符串。如果用户输入“Stenbeck", “Hemingway”,“Fitzgerald”,输出将是“Fitzgerald&#xff0c;Hemingway&…...

了解AIGC——自然语言处理与生成

AIGC——自然语言处理与生成&#xff1a;揭秘AI如何生成语言 近年来&#xff0c;AIGC&#xff08;AI Generated Content&#xff09;技术迅猛发展&#xff0c;自然语言处理&#xff08;Natural Language Processing, NLP&#xff09;与生成技术的结合&#xff0c;使得机器不仅…...

Modern CMake 简明教程(8)- 集成Qt

在项目中集成 Qt 库需要先使用 find_package 查找 Qt 的安装位置。对于 Qt4, CMake 使用 Module 模式进行查找(FindQt4.cmake 由 CMake 提供),而 对于 Qt5、Qt6,则是使用 Config 模式进行查找,相应的 config 文件位于类似下面的目录中 D:\Qt\5.15.2\msvc2019\lib\cmake。…...

人脸应用实例:性别年龄预测

在当今科技飞速发展的时代&#xff0c;人脸识别技术已经从科幻电影走进了我们的日常生活。通过算法来识别人脸的特征&#xff0c;进而判断身份、年龄和性别&#xff0c;这一技术正逐步改变着我们的生活方式。今天&#xff0c;我们就来探讨一下基于深度学习的人脸应用实例——性…...

学习threejs,通过THREE.Raycaster给模型绑定点击事件

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.Raycaster光线投射概…...

Jackson Json序列化反序列化的两个坑

Jackson is a suite of data-processing tools for Java (and the JVM platform) Jackson最常用的Json序列化功能&#xff0c;引入如下的包即可&#xff1a; <properties>...<!-- Use the latest version whenever possible. --><jackson.version>2.17.1<…...

k8s_Pod健康检查

Kubernetes 3种探针介绍 LivenessProbe&#xff08;存活探针&#xff09; LivenessProbe 用于检查容器是否仍然活着。如果探针检测到容器已经失去响应&#xff0c;Kubernetes 将重启该容器。这通常用来修复由于内部状态错误或死锁引起的程序失效问题。 作用&#xff1a;检测容器…...

基于DDPG算法的股票量化交易

项目源码获取方式见文章末尾&#xff01; 回复暗号&#xff1a;13&#xff0c;免费获取600多个深度学习项目资料&#xff0c;快来加入社群一起学习吧。 **《------往期经典推荐------》**项目名称 1.【基于PyQTFaceNet卷积神经网络实现的学生人脸识别考勤系统】 2.【卫星图像道…...

eIQ笔记(UI介绍+Loss曲线+OpenART例程)

This is a very beginner-friendly article ^o^ 目录 🍂一、训练器设置 input size: learning rate: learning rate decay: Epochs: Decay Rate: Linear Decay: Batch Size: Epochs to Train: QAT(Quantization Aware Training)量化感知训练: Pruning剪枝…...

微信小程序——消息订阅

首先用到的就是wx.requestSubscribeMessage接口。 注意&#xff1a;用户发生点击行为或者发起支付回调后&#xff0c;才可以调起订阅消息界面 requestSubscribeMessage() {uni.requestSubscribeMessage({tmplIds: [],//需要订阅的消息模板的id的集合&#xff0c;一次调用最多可…...

网络原理(传输层)->TCP协议解

前言 大家好&#xff01;我是小帅&#xff0c;今天我们来学习TCP协议&#xff0c;个人主页 文章目录 1. TCP协议2. TCP的核心机制2.1TCP核心机制一&#xff1a;确认应答2.2 TCP核心机制二&#xff1a;超时重传2.3 TCP核心机制三&#xff1a;连接管理2.4 TCP核心机制四&#xf…...

oracle imp和exp 导入不同库的用户和表空间

参考&#xff1a; oracle 导入(imp)数据时的表空间(tablespace users)问题_imp tablespace-CSDN博客 网上的解决办法大概都是这种&#xff0c;但是实际测试19c数据库并不能成功&#xff0c;所以最后采取在导出文件上强行修改表空间的办法&#xff0c;改完后再继续执行导出导入…...

滚珠丝杆的精度级别如何分?

滚珠丝杆是一种常见的线性传动装置&#xff0c;广泛应用于各种机械设备和自动化系统中。滚珠丝杆的精度等级划分是评估其传动精度和运动平稳度的重要标准&#xff0c;滚珠丝杆的精度级别划分主要基于传动中实际移动距离与理想移动距离的偏差&#xff0c;偏差越小&#xff0c;精…...

ComfyUI初体验

ComfyUI 我就不过多介绍了&#xff0c;安装和基础使用可以看下面大佬的视频&#xff0c;感觉自己靠图文描述的效果不一定好&#xff0c;大家看视频比较方便。 ComfyUI全球爆红&#xff0c;AI绘画进入“工作流时代”&#xff1f;做最好懂的Comfy UI入门教程&#xff1a;Stable D…...

DPI-C动态库so的使用

文章目录 前言一、方法介绍二、demo演示2.1 文件准备2.2 执行仿真2.3 仿真结果 总结 前言 在做IC验证EDA仿真过程中&#xff0c;有时候需要调用C实现的参考模块&#xff0c;我们可以利用DPI-C的功能&#xff0c;实现SV侧调用C侧的函数。 在具体实现过程中&#xff0c;我们可以…...

Java避坑案例 - 高并发场景下的分布式缓存策略

文章目录 概述缓存常见问题及解决方案把 Redis 当作数据库常用的数据淘汰策略如何选择合适的驱逐算法 缓存雪崩问题复现解决方案 缓存击穿&#xff08;热点缓存失效&#xff09;问题复现解决方案 缓存穿透问题复现解决方案缓存穿透 vs 缓存击穿 缓存与数据库的一致性先更新缓存…...

Python中的字符串修剪:strip()、lstrip() 和 rstrip()

Python中的字符串修剪 Python 中的字符串修剪&#xff1a;strip()、lstrip() 和 rstrip()strip()lstrip()rstrip()应用场景结论 Python 中的字符串修剪&#xff1a;strip()、lstrip() 和 rstrip() 在 Python 开发中&#xff0c;我们经常需要处理字符串&#xff0c;其中一项常见…...

K8S配置storage-class

简介 Kubernetes支持NFS存储&#xff0c;需要安装nfs-subdir-external-provisioner&#xff0c;它是一个存储资源自动调配器&#xff0c;它可将现有的NFS服务器通过持久卷声明来支持Kubernetes持久卷的动态分配。该组件是对Kubernetes NFS-Client Provisioner的扩展&#xff0…...

多线程——线程池

目录 前言 一、什么是线程池 1.引入线程池的原因 2.线程池的介绍 二、标准库中的线程池 1.构造方法 2.方法参数 &#xff08;1&#xff09;corePoolSize 与 maximumPoolSize &#xff08;2&#xff09;keepAliveTime 与 unit &#xff08;3&#xff09;workQueue&am…...

VScode插件:前端每日一题

大文件上传如何做断点续传&#xff1f; 在前端实现大文件上传的断点续传&#xff0c;通常会将文件切片并分块上传&#xff0c;记录每块的上传状态&#xff0c;以便在中断或失败时只上传未完成的部分。以下是实现断点续传的主要步骤和思路&#xff1a; 1. 文件切片 (File Slici…...

Android跨进程通信

1、跨进程通信的几种方式 在 Android 中&#xff0c;跨进程通信 (IPC, Inter-Process Communication) 方式有多种&#xff0c;主要用于在不同的应用或进程之间传递数据。常见的跨进程通信方式包括&#xff1a; AIDL (Android Interface Definition Language) • 描述&#xff…...

【初阶数据结构】计数排序 :感受非比较排序的魅力

文章目录 前言1. 什么是计数排序&#xff1f;2. 计数排序的算法思路2.1 绝对位置和相对位置2.2 根据计数数组的信息来确认 3. 计数排序的代码4. 算法分析5. 计数排序的优缺点6.计数排序的应用场景 前言 如果大家仔细思考的话&#xff0c;可能会发现这么一个问题。我们学的七大…...

前后双差速轮之LQR控制

在之前的代码中,我们实现了前后两对双差速轮AGV的运动学正解和逆解。但为了实现对AGV的精确路径跟踪和姿态控制,我们需要引入控制算法。线性二次型调节器(LQR)是一种常用的最优控制方法,可以有效地将系统的状态误差最小化。本文将详细说明如何在之前的C++代码中加入LQR控制…...

Linux之远程连接服务器

1、远程连接服务器简介 &#xff08;1&#xff09;什么是远程连接服务器 远程连接服务器通过文字或图形接口方式来远程登录系统&#xff0c;让你在远程终端前登录linux主机以取得可操作主机接口&#xff08;shell&#xff09;&#xff0c;而登录后的操作感觉就像是坐在系统前面…...

k8s 部署 nexus3 详解

创建命名空间 nexus3-namespace.yaml apiVersion: v1 kind: Namespace metadata:name: nexus-ns创建pv&pvc nexus3-pv-pvc.yaml apiVersion: v1 kind: PersistentVolume metadata:name: nfs-pvnamespace: nexus-ns spec:capacity:storage: 3GiaccessModes:- ReadWriteM…...

wordpress搭建的博客系统/推广平台免费b2b网站大全

题目描述 这是一道模板题。 给你两个多项式&#xff0c;请输出乘起来后的多项式。 输入格式 第一行两个整数 n 和 m&#xff0c;分别表示两个多项式的次数。 第二行 n1 个整数&#xff0c;分别表示第一个多项式的 0 到 n 次项前的系数。 第三行 m1 个整数&#xff0c;分别表示第…...

flash做网站的论文/搭建网站费用是多少

因为业务需求所以需要一个ID生成器&#xff0c;要求生成器16位ID唯一。UUID太长不适合需求&#xff0c;所以琢磨了一个。总体思路就是&#xff0c;借助UUID&#xff08;毕竟人家全球唯一&#xff0c;自己写太麻烦了&#xff09;生成一个baseID&#xff0c;然后搞个位权出来进行…...

全球外贸网站制作教程/网站域名综合查询

前言 在Linux系统如Ubuntu下做C语言编程常见的操作是&#xff1a;写好代码&#xff0c;然后使用gcc指令对程序预处理-编译-汇编-链接&#xff08;其实只用一条指令&#xff1a;gcc -o&#xff09;。这样的方法只适合单文件无文件组织的简单工程。当工程中代码文件增加且拥有组织…...

普洱专业企业网站建设/开封网站快速排名优化

问题描述  LIS(Longest Increasing Subsequence&#xff0c;最长递增子序列)&#xff1a;给出一个序 列a1,a2,a3,a4,a5,a6,a7…an&#xff0c;求它的一个子序列(设为s1,s2,…sn)&#xff0c;使得这个 子序列满足这样的性质&#xff0c;s1 最长递增子序列 实例分析 1 7 3 5 9 …...

asp制作网站教程/推广普通话作文

文章目录前言1. 题目2. 题目分析3. 四个python内置函数3.1 lower()方法3.2 ord()方法3.3 bin()方法3.4 count()方法4. 代码前言 再一次感受到了python的强大&#xff0c;这个题这么复杂的操作&#xff0c;python只用了4个函数&#xff0c;12行就搞定了。这次总结一下这4个函数…...

企业管理咨询网站模板/中国互联网协会官网

目录 公共文件 引入 拦截器 请求 验证码实例 后端接口 前端 跨域 公共文件 文件路径和名称&#xff1a;utils/api.js 引入 import axios from "axios"; import { Message } from element-ui; import router from "../router";//在拦截器中引入了ro…...