c++STL-vector的模拟实现
c++STL-vector的模拟实现
- vector的模拟实现
- 基本信息
- 构造函数
- 析构函数
- 返回容量(capacity)
- 返回元素个数(size)
- 扩容(reserve和resize)
- 访问([])
- 迭代器(**iterator**)
- 尾插(push_back)
- 插入(insert)
- 删除(erase)
- 拷贝构造
- 交换(swap)
- 赋值重载(operator=)
- 参考程序
vector的模拟实现
建议先看c++STL-string的模拟实现-CSDN博客。
string
的模拟实现用的是顺序表的模板。
这里的模拟实现模仿某个STL版本的vector
。
基本信息
库中的vector
用的是定位new
和内存池。这里的模拟实现不涉及内存池的概念,所有信息采用1个数组表示,用原始的堆模拟内存池。
template<class T>
class vector {
public:typedef T* iterator;//typedef会受到访问限定符影响typedef const T* const_iterator;
private:iterator _start;iterator _finish;iterator _endofstorage;
};
vector
的很多函数和string
类似。
模板类在类中可以不用写全类型。比如这里:
template<class T>
class vector {...vector f(vector& x){}
};
原本应该是vector<T>
,但这里不推荐去掉。
构造函数
vector
的拷贝构造需要用户实现,否则默认拷贝构造只会给浅拷贝。
这里选择三个构造函数接口进行模拟实现:
//无参构造函数
explicit vector (const allocator_type& alloc = allocator_type());//用n个val去初始化
vector (size_type n, const value_type& val,const allocator_type& alloc = allocator_type());//迭代器初始化
template <class InputIterator>vector (InputIterator first, InputIterator last,const allocator_type& alloc = allocator_type());
首先将全体指针初始化为nullptr
,然后根据构造对象用的形参填充数据。也就是说这里给出至少2个构造函数,只给指针初始化为nullptr
的,和用指定数据填充的。
其他构造函数根据vector - C++ Reference自行实现即可。
在类里面能写模板函数。构造函数用函数模板是为了能用不同类型的迭代器初始化。但如果两个的参数类型相同,可能会自动选择最匹配的
比如:
template<T>
class vector{
public:template<InputIterator>vector(InputIterator first,InputIterator second){...}vector(size_t n, T value=T()){...}
}void f(){vector<int>a(10,0);
}
我们肯定希望vector<int>a(10,0)
走的是vector(size_t n, T value=T())
,但编译器却为它匹配了vector(InputIterator first,InputIterator second)
。
所以针对这种情况,只能加一个vector(int n, const T& value=T())
的函数重载。
析构函数
直接delete[] _start;
即可。不用free
是因为T
可能是类。
返回容量(capacity)
返回_endofstorage-_start
即可。
返回元素个数(size)
返回_finish-_start
即可。
扩容(reserve和resize)
扩容时用new
,不用realloc
,原因是T
可能是类,需要调用构造函数。扩容时如果初始容量为0,需要给个非0值作为初始容量。
既然不用realloc
,那等于是每次扩容都是异地扩容,需要特别注意三个迭代器指向的空间,防止旧空间的迭代器和新空间的迭代器进行计算。
而且原来的数据可能不为空,所以需要将原来的数据深拷贝给新开的空间。不要用memcpy
拷贝数据,如果自己选的数据类型是自定义类型,会导致深层次的浅拷贝问题导致错误初始化。
即扩容时因为是异地扩容,所以需要将之前的数据拷贝到新数组,用
memcpy
的话只会将原数组存储的地址拷贝到新数组而不会调用构造函数,实际它们管理的还是原来的空间,当释放就空间时,新数组存储的地址就无效。所以需要用循环来深拷贝。
除非使用计数变量,或知道数据的位置。
reserve
:
判断是否有扩容的必要,即请求的容量大于初始容量时才进行扩容。
- 对象刚创建,经过构造函数初始化列表后指针全体为
nullptr
。这里给1个初始空间,实际上给不给都无所谓。 - 对象并非刚创建。则
_start
非空,需要将原来的数据拷贝给现在的数据,同时容量按2倍增速扩大。
resize
:
resize
是在reserve
的基础上将数据初始化为指定内容,在初始化时允许改变_finish
的值。
访问([])
返回具体下标即可。
需要加两个,一个可读可写,一个只读。
迭代器(iterator)
初学时用指针实现即可。
begin()
和end()
要给两个版本:只读(加const
修饰)和可读可写。
尾插(push_back)
- 插入前先检查是否需要扩容。扩容后尾指针赋值并自增1即可。
- 或先实现插入(
insert
),调用insert
间接实现即可。
和string
不同,因为用的是迭代器而不是size_t
,指针几乎不可能是0,所以头插可以不用特别注意。
但vector
的形参用的迭代器,一旦发生扩容,形参表示的迭代器会失效。所以需要记录偏移量,方便调整。
迭代器实参不能用引用,因为形参可能是函数。
插入(insert)
单个元素的插入:
- 插入前先判断插入的位置是否在两个指针之间,在的话再尝试扩容,否则越界访问。
- 之后挪动数据,将数据插入后,尾指针自增1。
多个元素的插入:
- 插入前先判断插入的位置是否在两个指针之间,在的话再尝试扩容,否则越界访问。
- 之后挪动合适数量的数据,将数据插入后,调整尾指针。
但无论是哪个,都要返回迭代器,防止迭代器失效的问题。
原容器没有指定下标插入,这里为了方便使用了下标标记。
删除(erase)
//删除指定位置的迭代器表示的
iterator erase (iterator position);
iterator erase (iterator first, iterator last);
需要先检查数组中是否还有元素。
后通过挪动数据覆盖即可。每次挪动完成后将尾指针自减。
迭代器实参不能用引用,因为形参可能是函数。
而且erase
同样有可能使迭代器失效。
拷贝构造
形参为引用。
当调用拷贝构造时,编译器生成一个新的临时对象,用形参的引用对象的数据赋值给新的临时对象。
因此拷贝构造函数需要进行深拷贝。
交换(swap)
因为是一个用三个指针指向空间的不同位置来实现,所以交换两个对象,交换它们的三个指针即可。
赋值重载(operator=)
//c++98自带的用vector对象进行拷贝构造
vector& operator= (const vector& x);
赋值重载的形参不用引用,使传参过程中会调用拷贝构造来生成形参的临时对象。
之后形参的临时对象和*this
,两个对象交换(swap
)成员指针即可,临时对象变成了*this
,并以*this
的面目活下去,而原*this
变成了临时对象调用析构函数。
参考程序
#pragma once
#include<cassert>namespace mystd {template<class T>void swap(T& a, T& b) {T tmp = a;a = b;b = tmp;}template<class T>class vector {public:typedef T* iterator;typedef const T* const_iterator;//构造函数vector<T>():_start(nullptr), _finish(nullptr), _endofstorage(nullptr){}vector<T>(size_t n, const T& val = T()): _start(nullptr), _finish(nullptr), _endofstorage(nullptr) {reserve(n);_finish = _start + n;for (size_t i = 0; i < n; i++) {_start[i] = val;}}//析构函数~vector<T>() {delete[]_start;_start = _finish = _endofstorage = nullptr;}//获取容量信息size_t capacity() const {return _endofstorage - _start;}//获取数量size_t size() const {return _finish - _start;}//扩容void reserve(size_t n) {while (n > capacity()) {size_t sz = size();size_t new_c = capacity();new_c = new_c == 0 ? n : new_c * 2;T* tmp = new T[new_c]{ T() };if (_start != nullptr) {for (size_t i = 0; i < sz; i++) {tmp[i] = _start[i];}}_start = tmp;_finish = tmp + sz;_endofstorage = tmp + new_c;}}void resize(size_t n, const T& val) {reserve(n);for (size_t i = size(); i < n; i++)_start[i] = val;_finish = _start + n;}//访问T& operator[](size_t pos) {assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const {assert(pos < size());return _start[pos];}//迭代器iterator begin() {return _start;}iterator end() {return _finish;}const_iterator begin() const {return _start;}const_iterator end() const {return _finish;}//插入//单个元素iterator insert(iterator pos, const T& val) {assert(pos >= begin());assert(pos <= end());size_t sz = pos - begin();//计算偏移量reserve(size() + 1);pos = begin() + sz;auto End = end();while (End > pos) {*End = *(End - 1);--End;}*End = val;_finish++;return pos;}//尾插void push_back(const T& val) {insert(end(), val);}//删除//删除指定迭代器iterator erase(iterator pos) {assert(pos >= begin());assert(pos < end());auto tmp = pos;while (tmp < _finish) {*tmp = *(tmp + 1);++tmp;}--_finish;return pos;}//删除区域的迭代器//左闭右开iterator erase(iterator Begin, iterator End) {assert(Begin >= begin());assert(End <= end());assert(Begin <= End);size_t sz = size_t(End - Begin);iterator tmp = Begin;while (tmp + sz < end()) {*tmp = *(tmp + sz);++tmp;}_finish = tmp;return Begin;}//尾删void pop_back() {erase(end() - 1);}//拷贝构造vector<T>(const vector<T>& a):_start(nullptr), _finish(nullptr), _endofstorage(nullptr) {reserve(capacity());for (auto& x : a)push_back(x);}//交换void swap(vector<T>& b) {vector<T>& a = *this;mystd::swap(a._start, b._start);mystd::swap(a._finish, b._finish);mystd::swap(a._endofstorage, b._endofstorage);}//赋值重载vector<T>& operator=(vector<T> tmp) {swap(tmp);return *this;}private:iterator _start;iterator _finish;iterator _endofstorage;};
}
相关文章:
c++STL-vector的模拟实现
cSTL-vector的模拟实现 vector的模拟实现基本信息构造函数析构函数返回容量(capacity)返回元素个数(size)扩容(reserve和resize)访问([])迭代器(**iterator**)…...
【Python 变量类型】
Python 是一种动态类型语言,变量类型在运行时自动确定,无需显式声明。以下是 Python 中核心变量类型的分类与用法详解: 一、基本数据类型 1. 数值类型 整数 (int) 支持正负数、零和二进制/八进制/十六进制表示: a 42 b 0o52 #…...
2.2 微积分的解释
第一阶段:曲直转化的数学革命 原始困境: 几何局限:古希腊几何仅能计算矩形/三角形等直线图形面积现实需求:17世纪弹道轨迹、行星轨道等曲线相关计算需求激增关键矛盾:直线数学工具(如毕达哥拉斯定理&…...
如何使用Selenium?
Selenium 是一个用于 Web 自动化测试 的开源工具套件,支持多种浏览器和编程语言。它最初是为测试 Web 应用而设计,但也被广泛用于 网页数据抓取 和 自动化操作。 Selenium 的核心组件 Selenium WebDriver 直接控制浏览器,模拟用户操作&…...
SVN 中文路径访问报错(权限已正确分配)
问题:SVN 中文路径访问报错(权限已正确分配) 原因: 1、URL特殊字符未转义 路径中包含空格、中文括号()等特殊符号,未进行URL编码 中文括号()示例:(设计)需转为%28%E8%AE%BE%E8%AE%A1%29,空格需…...
【Python 基础语法】
Python 基础语法是编程的基石,以下从核心要素到实用技巧进行系统梳理: 一、代码结构规范 缩进规则 使用4个空格缩进(PEP 8标准)缩进定义代码块(如函数、循环、条件语句) def greet(name):if name: # 正确缩…...
讲讲git 和svn
讲讲git 和svn 目录Git到底是什么?它该怎末用?核心概念基础操作1. 仓库的创建2. 文件的提交工作流程3. 分支管理4. 远程仓库操作 进阶操作实际应用建议**基本用法****常用命令的帮助示例****帮助文档的结构****替代方法****练习建议****核心概念****与Gi…...
运用数组和矩阵对数据进行存取和运算——NumPy模块 之四
目录 NumPy模块介绍 3.4 NumPy 数组重塑与转置 3.4.1 操作机制的理论逻辑 3.4.2 一维数组的重塑 3.4.3 多维数组的重塑 3.4.4 数组的转置操作 3.4.5 知识点总结与课程回顾 3.4.6 课后练习题 NumPy模块介绍 NumPy 是 Python 科学计算领域的重要基石,与当前 “躺吃旅行…...
机器学习第六讲:向量/矩阵 → 数据表格的数学表达,如Excel表格转数字阵列
机器学习第六讲:向量/矩阵 → 数据表格的数学表达,如Excel表格转数字阵列 资料取自《零基础学机器学习》。 查看总目录:学习大纲 关于DeepSeek本地部署指南可以看下我之前写的文章:DeepSeek R1本地与线上满血版部署:…...
服务器多JAR程序运行与管理指南
在同一台服务器上同时运行多个JAR程序是完全可以的,但需要注意以下几点以确保稳定性和性能: 关键注意事项 端口冲突 如果JAR程序是网络服务(如Web应用),确保每个程序监听不同的端口(例如:8080、…...
vue实现进度条带指针
效果最终 function calculatePointerPosition(value) {if (value < 2.6) return 12.5; // 非常差位置if (value < 5.1) return 37.5; // 较差位置if (value < 7.1) return 62.5; // 良好位置return 90; // 非常满意位置 }function getStatusText(value) {if (valu…...
【C++】智能指针
前言 上文我们学到了C11的异常,了解到了C与C语言处理错误的区别,异常的特点在于抛出与接收。【C11】异常-CSDN博客 本文我们来学习C中的下一个功能:智能指针 1.智能指针的使用场景 在上文我们知道了抛异常的知识,抛异常的“抛”这…...
Adobe Acrobat pro在一份PDF中插入空白页
在Adobe Acrobat pro中先打开我们的PDF文件; 用鼠标点击需要插入空白页处的上一页; 然后如下图操作: 默认会在光标处的下一页插入一张空白页,你也可以修改插入页的页码或者向前一页插入...
Oracle adg环境下调整redo日志组以及standby日志组大小
1.在adg环境中,调整redo日志组大小以及standby日志组大小主要思路如下: a、先备库增加standby redo 删除老standby redo, b、然后主库增加redo删除老redo, c、备库增加新redo删除老redo, d、最后主库增加standby redo。 #主库 [oracleDB196 ~]$ sql / a…...
Nlog适配达梦数据库进行日志插入
前言 原来使用的是SQLServer数据库,使用Nlog很流畅,没有什么问题。现在有个新项目需要使用麒麟操作系统和达梦数据库,业务流程开发完成之后发现Nlog配置文件中把数据库连接内容修改之后不能执行插入操作。 原Nlog.config配置 <?xml ve…...
记一次redis未授权被种挖矿
#挖矿程序 /etc/httpgd /etc/nnt.sh #大小问 #定时任务名为root /var/spool/cron/root 内容:*/50 * * * * sh /etc/nnt.sh >/dev/null 2>&1 定时任务只有所有者可以写,且chmod修改权限失败。 #先查看定时任务的拓展属性,不可变(i…...
Docker私有仓库实战:官方registry镜像实战应用
抱歉抱歉,离职后反而更忙了,拖了好久,从4月拖到现在,在学习企业级方案Harbor之前,我们先学习下官方方案registry,话不多说,详情见下文。 注意:下文省略了基本认证 TLS加密ÿ…...
LeetCode 热题 100_只出现一次的数字(96_136_简单_C++)(哈希表;哈希集合;排序+遍历;位运算)
LeetCode 热题 100_只出现一次的数字(96_136_简单_C) 题目描述:输入输出样例:题解:解题思路:思路一(哈希表):思路二(哈希集合):思路三…...
基于FastAPI框架的日志模块设计
以下是一个基于FastAPI框架设计的日志模块,结合SQLite数据库实现增删改查功能的完整实现方案: 1. 项目结构 your_project/ ├── app/ │ ├── logs/ # 日志模块目录 │ │ ├── models.py # 数据库模型定义 │ │ …...
网页禁止粘贴的解决方法(以学习通网页为例)
网页禁止粘贴的解决方法(以学习通网页为例) 学数据挖掘,学习通过作业的简答题要英文做答还竟然不能复制粘贴,受不了了 下面给出解决办法 1.想着是网页JS的问题,既然不能直接粘贴,那就在源码里面修改 2.于…...
Linux常用命令详解(下):打包压缩、文本编辑与查找命令
一、打包压缩命令 在Linux系统中,打包与压缩是文件管理的核心操作之一。不同的工具适用于不同场景,以下是最常用的命令详解: 1. tar命令 作用:对文件进行打包、解包、压缩、解压。 语法: tar [选项] [压缩包名] […...
前端面经 计网 http和https区别
HTTP 超文本传输 忒点: 支持CS 客户/服务器模式 方便快捷 简单 允许传输任意类型的数据 在报文头中的Content-Type中声明 无连接,一次连接仅处理一个请求 无状态 不保留上一次的状态 HTTPS 解决HTTP明文传输 在HTTP基础上增加SSL协议 HTTP版本 …...
mac一键安装gpt-sovit教程中,homebrew卡住不动的问题
mac一键安装gpt-sovit教程 仅作为安装过程中解决homebrew卡住问题的记录 资源地址 https://www.yuque.com/baicaigongchang1145haoyuangong/ib3g1e/znoph9dtetg437xb#mlAoP 下载一键包 下载后并解压,找到install for mac.sh,终端执行bash空格拖拽in…...
05_jdk8新特性
文章目录 一、jdk8新特性1. Lambda表达式2. Stream API3. 函数式接口4. 默认方法5. 方法引用6. 新的日期和时间API7. Optional类8. 并发增强 二、常用函数式接口1. Supplier<T>2. Consumer<T>3. Function<T,R>4. Predicate<T> 一、jdk8新特性 JDK 8&a…...
解决IDEA Maven编译时@spring.profiles.active@没有替换成具体环境变量的问题
如果不加filtering true,编译后的文件还是 spring.profiles.active 编译前的application.yml 编译后的application.yml【环境变量没有改变】 解决方案 找到 SpringBoot 启动类所在的pom.xml,在 resources 增加 filtering true,然后重新…...
HTML17:表单初级验证
表单初级验证 常用方式 placeholder 提示信息 <p>名字:<input type"text" name"username" maxlength"8" size"30" placeholder"请输入用户名"></p>required 非空判断 <p>名字:<input type"…...
vue3+dhtmlx-gantt实现甘特图展示
最终效果 数据源demo {"data": [{"actual_end_date": "2025-04-23","actual_start_date": "2025-04-15","duration": 10,"end_date": "2025-05-01","id": "2|jvUiek",&…...
Jupyter-AI Pandas-AI本地使用功能优化
引言 Jupyter-ai 和 Pandas-ai 的优化主要是个人工作遇到的需求,个人觉得是一个不错的体验优化,所以进行分享仅供参考,不喜勿喷,共同进步!Jupyter-AI优化主要包含以下方向(当前已实现): Jupyter-AI中 Chat 扩展和 NoteBook 的 Cell 工作去部分,使用的Language Model 和 …...
Model.eval() 与 torch.no_grad() PyTorch 中的区别与应用
Model.eval() 与 torch.no_grad(): PyTorch 中的区别与应用 在 PyTorch 深度学习框架中,model.eval() 和 torch.no_grad() 是两个在模型推理(inference)阶段经常用到的函数,它们各自有着独特的功能和应用场景。本文将详细解析这两…...
mac M2下的centos8:java和jenkins版本匹配,插件安装问题
java和jenkins版本匹配如下: Java Support Policy 如果版本不匹配,jenkins无法正常启动,插件也无法安装成功。 实际操作过程发现:表格也并不全然正确,还是需要特定的版本才能正常 参考如下: jenkins安装…...
PyTorch 中的 Autograd 实现细节解析和应用
摘要: 本文深入探讨 PyTorch 框架的核心组件之一——Autograd 机制。我们将解析其内部工作原理,包括计算图的构建、梯度的计算与传播,并探讨其在神经网络训练、模型调试及可解释性等方面的广泛应用。 通过理解 Autograd 的实现细节,开发者可以更高效地利用 PyTorch 进行深度…...
【AI提示词】波特五力模型专家
提示说明 具备深入对企业竞争环境分析能力的专业人士。 提示词 # Role:波特五力模型专家## Profile - language:中文 - description:具备深入对企业竞争环境分析能力的专业人士 - background:熟悉经济学基础理论,擅长用五力模型分析行业竞争 - personality…...
python 的 uv、pip 和 conda 对比和技术选型
你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益: 了解大厂经验拥有和大厂相匹配的技术等 希望看什么,评论或者私信告诉我! 文章目录 一…...
《Python星球日记》 第63天:文本方向综合项目(新闻分类)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、项目需求分析1. 项目背景与目标2. 功能需求3. 技术方案概述 二、数据清洗与…...
面试题:请解释Java中的设计模式,并举例说明单例模式(Singleton Pattern)的实现方式
Java中的设计模式 设计模式是在软件开发过程中针对特定场景而使用的通用解决方案。设计模式可以帮助开发者编写出更加清晰、灵活和可维护的代码。设计模式分为三大类: 创建型模式:用于对象的创建过程,如单例模式、工厂模式、建造者模式等。…...
MySQL全量、增量备份与恢复
目录 一:MySQL数据库备份概述 1.数据备份的重要性 2.数据库备份类型 2.1从物理与逻辑的角度分类 物理备份 逻辑备份 2.2从数据库的备份策略角度分类 完全备份 差异备份 增量备份 3.常见的备份方法 3.1物理冷备份 3.2专用备份工具 MySQL dump或MySQL hot…...
rust 全栈应用框架dioxus server
接上一篇文章dioxus全栈应用框架的基本使用,支持web、desktop、mobile等平台。 可以先查看上一篇文章rust 全栈应用框架dioxus👈 既然是全栈框架,那肯定是得有后端服务的,之前创建的服务没有包含后端服务包,我们修改…...
Clinica集成化的开源平台-神经影像研究
Clinica集成化的开源平台-神经影像研究 🌟 Clinica集成化的开源平台-神经影像研究引言 🛠️ 一、环境搭建与数据准备1. 安装Clinica(附避坑指南)2. 数据标准化(BIDS格式处理) 🧠 二、sMRI预处理…...
LabVIEW中算法开发的系统化解决方案与优化
在 LabVIEW 开发环境中,算法实现是连接硬件数据采集与上层应用的核心环节。由于图形化编程范式与传统文本语言存在差异,LabVIEW 中的算法开发需要特别关注执行效率、代码可维护性以及与硬件资源的适配性。本文从算法架构设计、性能优化到工程实现&#x…...
【Pandas】pandas DataFrame cov
Pandas2.2 DataFrame Computations descriptive stats 方法描述DataFrame.abs()用于返回 DataFrame 中每个元素的绝对值DataFrame.all([axis, bool_only, skipna])用于判断 DataFrame 中是否所有元素在指定轴上都为 TrueDataFrame.any(*[, axis, bool_only, skipna])用于判断…...
【递归、搜索与回溯】专题一:递归(一)
📝前言说明: 本专栏主要记录本人递归,搜索与回溯算法的学习以及LeetCode刷题记录,按专题划分每题主要记录:(1)本人解法 本人屎山代码;(2)优质解法 优质代码…...
pythonocc 拉伸特征
micromamba install -c conda-forge pythonocc-core opencascade.js安装不起来,ai用pythonocc练个手 拉伸线框 线成面 from OCC.Core.gp import gp_Pnt, gp_Dir, gp_Vec from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeWire f…...
防爆手机与普通手机有什么区别
在石油化工、矿山能源、危化品运输等特殊行业中,一部手机的选择可能直接关系到生产安全与人员生命。防爆手机作为工业安全通信的核心工具,与日常使用的普通手机存在本质差异。本文将从技术原理、安全标准、功能设计及适用场景等维度,解析二者…...
动手学深度学习12.3.自动并行-笔记练习(PyTorch)
以下内容为结合李沐老师的课程和教材补充的学习笔记,以及对课后练习的一些思考,自留回顾,也供同学之人交流参考。 本节课程地址:无 本节教材地址:12.3. 自动并行 — 动手学深度学习 2.0.0 documentation 本节开源代…...
第二十二天打卡
数据预处理 import pandas as pd from sklearn.model_selection import train_test_splitdef data_preprocessing(file_path):"""泰坦尼克号生存预测数据预处理函数参数:file_path: 原始数据文件路径返回:preprocessed_data: 预处理后的数据集""&quo…...
SET NX互斥功能的实现原理
Redis 的 SET key value NX 命令通过其原子性和底层数据结构的特性实现互斥功能,具体实现如下: 1. 互斥功能的实现原理 SET NX 的核心是 原子性操作:当且仅当键(key)不存在时,才会设置键的值。Redis 的单线…...
前端 CSS 样式书写与选择器 基础知识
1.CSS介绍 CSS是Cascading Style Sheet的缩写,中文意思为"层叠样式表",它是网页的装饰者,用来修饰各标签 排版(大小、边距、背景、位置等)、改变字体的样式(字体大小、字体颜色、对齐方式等)。 2.CSS书写位置 2.1 样式表特征 层…...
一小时学会Docker使用!
文章目录 前言一、安装ssh连接工具二、安装docker三、Docker常见命令四、docker-compose使用 前言 Docker: Docker简单来说就是简化环境配置的,我们配置环境只需要简单的docker pull,docker run即可,而删除环境也很容易ÿ…...
android studio开发aar插件,并用uniapp开发APP使用这个aar
android studio开发aar插件,并用uniapp开发APP使用这个aar 使用android studio打包aar和Unity导入aar详解...
操作系统实战——QEMU模拟器搭建【rCore 操作系统】
操作系统大作业——QEMU模拟器搭建rCore操作系统 按照本篇步骤走,帮你少走很多弯路!博主在自己做的过程中踩了很多坑,过程还是很痛苦的,走了很多弯路,现在都已经在文章中把坑填平了,把弯路修直了。 创作不易…...