【C++】详解RAII思想与智能指针
🌈 个人主页:谁在夜里看海.
🔥 个人专栏:《C++系列》《Linux系列》
⛰️ 丢掉幻想,准备斗争
目录
引言
内存泄漏
内存泄漏的危害
内存泄漏的处理
一、RAII思想
二、智能指针
1.auto_ptr
实现原理
模拟实现
弊端
2.unique_ptr
实现原理
模拟实现
实现原理
模拟实现
循环引用问题
4.weak_ptr
引言
上一篇关于异常处理的文章,我们提到,异常处理是存在内存泄漏风险的,由于异常捕获会导致程序运行时执行流的跳转,并且在某些资源释放之前就进行了跳转,此时就会引发内存泄漏,来看下面这段代码:
当我输入3 0时,程序会抛出除零错误,并跳过了 delete p1; delete p2; 语句,因为异常发生时,程序的执行流会跳转到 catch 块,导致析构函数没有执行,引发内存泄漏。
内存泄漏
什么是内存泄漏呢?内存泄漏是指程序在运行的过程中,动态分配的内存被占用但没有得到释放,从而导致资源不能被回收,最终可能导致系统性能下降甚至崩溃。
内存泄漏的危害
1.如果内存泄漏非常严重,程序将消耗所有的可用内存,导致操作系统或程序本身的崩溃。
2.内存泄漏意味着分配的内存空间无法被回收,不仅浪费内存空间,还可能会影响其他进程。
3.在一些长期运行的系统(服务器、嵌入式设备等)中,内存泄漏会导致系统持续消耗内存而不释放,久而久之会导致系统性能下降并最终导致系统崩溃。
4.内存泄漏往往是隐蔽性的,在大规模且复杂的程序中,调试和定位内存泄漏非常困难,这时可能需要借助一些外部的工具。
内存泄漏的处理
一般分为两种:①事先预防型 ②事后查错型
事后查错型例如借助外部工具;
我们下面要介绍的就是对内存泄漏的事先预防处理办法,采用RAII思想以及智能指针:
一、RAII思想
RAII 全称 Resource Acquisition Is Initialization,中文翻译:资源获取即初始化,它强调通过对象的生命周期来管理资源,将资源的获取与释放与对象的创建与销毁相一致,RAII设计原则可以更好地管理动态资源,有效避免内存泄漏。还是用上述例子来直观感受一下:
template<class T>
class smartptr {
public:smartptr(T data){cout << "smartptr(T data)" << endl;_ptr = new T(data);}~smartptr(){cout << "~smartptr()" << endl;delete _ptr;}private:T* _ptr;
};int div()
{int a, b;cin >> a >> b;if (b == 0)throw invalid_argument("除0错误");return a / b;
}
int main()
{try{smartptr<int> p1(1);smartptr<int> p2(2);div();}catch (exception& e){cout << e.what() << endl;}return 0;
}
我们可以看到,RAII思想实际上就是将资源的获取与释放封装到一个类中,在构造函数中获取资源,在析构函数中释放资源。我们不需要显式地释放资源,并且将资源与对象的生命周期绑定
输入3 0时,抛出除零异常,执行流跳转的同时,try块内部生命周期结束,此时会调用内部对象的析构函数,完成了资源的释放,避免了资源泄露。
二、智能指针
上述smartptr还不能被称作智能指针,因为它不具备指针的行为,我们还需要在类内部重载解引用*、访问->等操作,使其能像指针一样使用:
template<class T>
class smartptr {
public:smartptr(T data = T()){_ptr = new T(data);}~smartptr(){delete _ptr;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}
private:T* _ptr;
};struct Date {int _year;int _month;int _day;
};int main()
{smartptr<Date> p1;p1->_year = 2024;p1->_month = 11;p1->_day = 9;cout << (*p1)._year << "-" << (*p1)._month << "-" << (*p1)._day << endl;return 0;
}
智能指针采用RAII原理来管理动态分配的内存,也是将资源的管理与对象的生命周期绑定,并且可以像普通指针那样进行*、->等操作。
下面我们来介绍一下C++98提供的auto_ptr智能指针:
1.auto_ptr
auto_ptr是C++98标准引入的一种智能指针,是RAII思想的体现,其核心功能是自动管理动态分配的内存,确保指针在超出作用域时,资源被正确释放,下面是它的主要实现原理:
实现原理
构造函数
auto_ptr的构造函数接受一个原始指针(裸指针),并将其封装成auto_ptr对象内部的指针:
auto_ptr<int> p(new int(10)); // 构造函数
析构函数
auto_ptr的析构函数会在对象生命周期结束时自动调用delete操作符,释放指针所指向的内存:
~auto_ptr() {delete _ptr; // 释放内存
}
拷贝构造函数
与普通对象的拷贝构造函数不同,auto_ptr在拷贝时会转移其资源所有权给新对象。因此,拷贝构造后,原对象会变成一个空指针(指向nullptr)
auto_ptr(const auto_ptr& other) : _ptr(other._ptr) {other._ptr = nullptr; // 将原对象的指针设为 nullptr,避免重复释放
}
赋值操作符
auto_ptr的赋值操作符也会转移资源所有权,先释放当前对象的资源,然后将传入的指针复制到当前对象,并将传入指针置空:
auto_ptr& operator=(const auto_ptr& other) {if (this != &other) {delete _ptr; // 先释放当前资源_ptr = other._ptr;other._ptr = nullptr; // 将 other 的指针置空}return *this;
}
成员访问
通过重载*、->实现指针的解引用与访问成员操作:
auto_ptr<int> p(new int(10));
*p = 20; // 访问值
模拟实现
下面是对auto_ptr的简单模拟实现:
template<class T>class auto_ptr{public:// 构造函数auto_ptr(T* ptr):_ptr(ptr){}// 拷贝构造函数auto_ptr(auto_ptr<T>& other):_ptr(other._ptr){// 管理权转移other._ptr = nullptr;}// 赋值函数auto_ptr operator=(const auto_ptr<T> other){// 检测是否给自己赋值if (*this != other){// 释放当前资源if (_ptr)delete _ptr;_ptr = other._ptr;other._ptr = nullptr;}return *this;}// 析构函数~auto_ptr(){if(_ptr)delete _ptr;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;};
弊端
auto_ptr在拷贝和赋值时隐式地转移了资源所有权,会导致一些潜在的资源管理问题。
auto_ptr被拷贝时,源对象指针被置空,此时无法再进行访问:
auto_ptr<int> p1(new int(10)); // 创建 p1
auto_ptr<int> p2 = p1; // p1 的资源转移给 p2,p1 变为 nullptr
cout << *p1 << std::endl; // 错误,p1 已为空指针
这种隐性的资源转移,使得auto_ptr在传递和返回时不直观,比如,我们在函数调用对象时,希望资源可以被复制并共享,但是auto_ptr不允许资源的共享,可能会导致意料之外的资源转移:
void foo(auto_ptr<int> ptr) {// ptr 的资源所有权已经转移到 foo 函数的局部变量中
}int main() {auto_ptr<int> p1(new int(10));foo(p1); // p1 的资源被转移到 foo,p1 变为空指针cout << *p1 << std::endl; // 错误,p1 已为空指针
}
auto_ptr在实际使用过程中,会引发许多不易察觉的错误,这并不是我们想要的智能指针,为了避免上述问题,C++11引入了更多新的智能指针,例如unique_ptr:
2.unique_ptr
为了避免所有权转移导致的一系列潜在问题,unique_ptr采用了一种简单粗暴的办法:禁止拷贝,禁止一切拷贝行为,从根源上解决了问题。
实现原理
禁止拷贝行为
编译器会禁止unique_ptr的拷贝构造与拷贝复制操作,试图拷贝将会报错:
std::unique_ptr<int> p1(new int(10));
// 编译错误,禁止拷贝构造
std::unique_ptr<int> p2 = p1; // 错误:拷贝构造被删除
明确的资源所有权转移
禁止拷贝并不意味着对资源所有权转移的全面封杀,实际上还是可以对资源进行转移的,只不过auto_ptr是隐式地转移,而unique_ptr是显式地进行转移:
unique_ptr<int> p1(new int(10));
unique_ptr<int> p2 = move(p1); // 明确转移资源所有权// p1 现在为空指针,p2 拥有资源
cout << *p2 << endl; // 输出 10
// cout << *p1 << endl; // 错误:p1 现在为空指针
模拟实现
那么unique_ptr在底层是怎么实现对拷贝的禁止的呢,其实是用到了delete关键字,在成员函数后面加上 = delete,表示禁止该成员函数的使用,通过delete删除拷贝构造函数与拷贝赋值函数,从而禁止了拷贝行为的发生:
template<class T>class unique_ptr{public:unique_ptr(T* ptr):_ptr(ptr){}~unique_ptr(){if (_ptr)delete _ptr;}// 指针操作T& operator*(){return *_ptr;}T* operator->(){return _ptr;}// 不支持拷贝构造、拷贝赋值unique_ptr(const unique_ptr<T>& other) = delete;unique_ptr operator=(const unique_ptr<T> other) = delete;private:T* _ptr;};
C++11还提供了一种智能指针,它支持拷贝行为,并且允许多个对象共享资源,即拷贝赋值并不会将原指针置空,而是让它们指向同一块空间:
3.shared_ptr
shared_ptr支持拷贝构造以及拷贝赋值,它们可以共享资源,各自进行操作,但要考虑一个问题:RAII的思想是将资源的获取和释放与对象的生命周期绑定,当我通过函数传参的方式将一个对象赋值给了另一个对象,会导致资源的提前释放(函数结束),这样外部指针就悬空了,共享的资源只需要进行一次释放即可,那么我们怎么知道何时释放资源呢?通过计数器的方式实现:
实现原理
shared_ptr
通过引用计数来实现资源的正确释放,确保在所有共享该资源的shared_ptr
对象都销毁后才释放资。
当另一个shared_ptr对象拷贝构造或者赋值时,引用计数增加,表示多了一个对象在共享资源;当shared_ptr对象析构或被赋值到新的对象时,引用计数减少,表示减少一个共享资源的持有者。
模拟实现
实现过程如下:
template<class T>class shared_ptr{public:shared_ptr(T* ptr):_ptr(ptr),_pCount(new int(0)){++* _pCount; // 增加计数}shared_ptr(shared_ptr<T>& other):_ptr(other._ptr),_pCount(other._pCount){cout << "shared_ptr(shared_ptr<T>& other)" << endl;++* _pCount; // 增加计数}shared_ptr operator=(shared_ptr<T>& other){// 检测是否给自己赋值if (_ptr != other._ptr){cout << "shared_ptr operator=(const shared_ptr<T>& other)" << endl;--* _pCount; // 减少当前资源的计数// 释放当前资源if (*_pCount == 0){delete _ptr;delete _pCount;}_ptr = other._ptr;_pCount = other._pCount;++* _pCount; // 增加新资源的计数}return *this;}~shared_ptr(){--* _pCount; // 减少计数if (*_pCount == 0){// 共享对象全部销毁,进行析构cout << "~shared_ptr()" << endl;delete _ptr;delete _pCount;}}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;int* _pCount;};
shared_ptr适用于绝大多数场景,但是在某些场景下,会引发循环引用问题,此时资源不能得到正确释放:
循环引用问题
来看下面这段代码:
struct ListNode
{int _data;shared_ptr<ListNode> _prev;shared_ptr<ListNode> _next;~ListNode() { cout << "~ListNode()" << endl; }
};
int main()
{shared_ptr<ListNode> node1(new ListNode);shared_ptr<ListNode> node2(new ListNode);cout << node1.use_count() << endl;cout << node2.use_count() << endl;node1->_next = node2;node2->_prev = node1;cout << node1.use_count() << endl;cout << node2.use_count() << endl;return 0;
}
我们将节点的_prev和_next定义成shared_ptr智能指针,并定义了两个节点,节点2的_prev指向节点1,节点1的_next指向节点2:
这个时候会造成什么结果呢,我们来看运行结果:
node1的_next和node2共享资源,所以它们的计数为2,node2的_prev和node1共享资源,所以它们的计数也为2,从运行结果可以看出,节点空间没有得到释放(没有打印"~ListNode()"内容),这是为什么呢?
由于Node1和Node2的相互引用,它们的任意一个要想释放空间,都得建立在对方已经释放空间的基础上,于是乎两者都不能正常进行空间释放,这就是循环引用问题。
4.weak_ptr
C++11提供了一种弱引用智能指针weak_ptr,它的出现就是为了解决循环引用问题的,其原理是:weak_ptr是对对象的弱引用,不会增加计数,不会阻止资源的释放。
由于互相指向时,计数没有增加,所以最后析构函数正常调用,资源得到释放。
以上就是对RAII思想及智能指针的介绍与个人理解,欢迎指正~
码文不易,还请多多关注支持,这是我持续创作的最大动力!
相关文章:
【C++】详解RAII思想与智能指针
🌈 个人主页:谁在夜里看海. 🔥 个人专栏:《C系列》《Linux系列》 ⛰️ 丢掉幻想,准备斗争 目录 引言 内存泄漏 内存泄漏的危害 内存泄漏的处理 一、RAII思想 二、智能指针 1.auto_ptr 实现原理 模拟实现 弊端…...
Qt 环境实现视频和音频播放
在这个示例中,我们将使用 FFmpeg 进行视频和音频的解码,并使用 Qt 的界面进行显示和控制。为了实现音频和视频的解码以及同步显示,我们需要使用 FFmpeg 的解码库进行视频和音频解码,使用 Qt 的 QLabel 显示解码后的视频帧…...
【人工智能训练师】7 大数据处理与应用
大数据处理与应用(Hive技术)(0/100分) 1.本地开发工具连接Hadoop集群 1.本次环境版本为Hadoop2.7.7,对应eclips插件存放于云主机master:/usr/package277/中。 2.本机映射名为hadoop000,云主机Hadoop/Hive的hosts文件中IP需要修改…...
nginx配置文件介绍及示例
一、nginx配置文件一共有main,http,server,location,upstream,stream,events7个块。 step 1: main 块 作用:main 块是 Nginx 配置文件的顶级块,用于设置一些全局的参数和配置&…...
如何在算家云搭建YOLOv5(物体检测)
一、YOLOv5简介 YOLOv5 模型是一种以实时物体检测闻名的计算机视觉模型,由 Ultralytics 开发,并于 2020 年年中发布。它是 YOLO 系列的升级版,继承了 YOLO 系列以实时物体检测能力而著称的特点。 二、模型搭建流程 1.选择模型实例 在应用…...
现场工程师日记-MSYS2迅速部署PostgreSQL主从备份数据库
文章目录 一、概要二、整体架构流程1. 安装 MSYS2 环境2. 安装postgresql 三、技术名词解释1.MSYS22.postgresql 四、技术细节1. 创建主数据库2.添加从数据库复制权限3. 按需修改参数(1)WAL保留空间(2)监听地址 4. 启动主服务器5.…...
使用Element UI实现一个拖拽图片上传,并可以Ctrl + V获取图片实现文件上传
要在 Element UI 的拖拽上传组件中实现 Ctrl V 图片上传功能,可以通过监听键盘事件来捕获粘贴操作,并将粘贴的图片数据上传到服务器。 版本V1,实现获取粘贴板中的文件 注意,本案例需要再你已经安装了Element UI并在项目中正确配…...
私域流量圈层在新消费时代的机遇与挑战:兼论开源 AI 智能名片、2 + 1 链动模式、S2B2C 商城小程序的应用
摘要:本文剖析了私域流量圈层在新消费时代呈现出的独特温度与信任优势,阐述了从传统销售到新消费转型中用户心理的变化。同时,强调了内容对于私域流量的关键作用,并分析开源 AI 智能名片、2 1 链动模式、S2B2C 商城小程序在私域流…...
vxe-vxe-colgroup后端返回数据 对数据进行处理 动态合并分组表头(v-if控制表格渲染(数据请求完成后渲染))
1.html vxe-colgroup循环合并数据;v-if控制表格渲染(数据请求完成后渲染) <template><vxe-table v-if"isTableReady" :data"tableData"><vxe-colgroup title"基本信息"><template v-for…...
ESLint 使用教程(五):从输入 eslint 命令到最终代码被处理,ESLint 中间究竟做了什么工作
前言 ESLint 是现代 JavaScript 开发中不可或缺的代码质量工具。它能够帮助开发者找到并修复代码中的问题,提升代码的可维护性。但是,你可能会好奇:从我们在终端里输入 eslint 命令到最终代码被处理,ESLint 中间究竟做了什么工作…...
【安全测试】sqlmap工具(sql注入)学习
前言:sqimap是一个开源的渗透测试工具,它可以自动化检测和利用SQL注入缺陷以及接管数据库服务器的过程。它有一个强大的检测引擎,许多适合于终极渗透测试的小众特性和广泛的开关,从数据库指纹、从数据库获 取数据到访问底层文件系…...
YOLOv11融合CVPR[2023]空间和通道重建卷积ScConv模块及相关改进思路|YOLO改进最简教程
YOLOv11v10v8使用教程: YOLOv11入门到入土使用教程 YOLOv11改进汇总贴:YOLOv11及自研模型更新汇总 《SCConv: Spatial and Channel Reconstruction Convolution for Feature Redundancy》 一、 模块介绍 论文链接:SCConv: Spatial and Cha…...
C++研发笔记13——C语言程序设计初阶学习笔记11
从今天开始我们开始第三模块《分支语句和循环语句》的学习,在本模块中我们将会涉及到以下9个内容:什么是语句、分支语句——if语言、分支语句——switch语句、循环语句——while循环、循环语句——for循环、循环语句——do while循环、折半查找算法、猜数…...
html5拖放
1、什么是拖放(Drag 和 Drop) 拖放,字面意思就是拖动,放置 在编程里面也是如此,拖放是一种常见的特性,即抓取对象以后拖到另一个位置。 在 HTML5 中,拖放是标准的一部分,任何元素都能够拖放。…...
卫导调零天线功率倒置算法原理及MATLAB仿真
卫导调零天线功率倒置算法原理及MATLAB仿真 文章目录 前言一、调零天线简介二、功率倒置自适应算法三、MATLAB仿真四、MATLAB代码总结 前言 \;\;\;\;\; 自适应调零抗干扰技术可以很大程度改善导航抗干扰性能,也是目前导航抗干扰技术中不可或缺的,其研究意…...
【划分型 DP】力扣139. 单词拆分
给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。 注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。 示例 1: 输入: s “leetcode”, wordDic…...
Python学习从0到1 day26 第三阶段 Spark ④ 数据输出
半山腰太挤了,你该去山顶看看 —— 24.11.10 一、输出为python对象 1.collect算子 功能: 将RDD各个分区内的数据,统一收集到Driver中,形成一个List对象 语法: rdd.collect() 返回值是一个list列表 示例: from …...
AWTK fscript 中的 JSON 扩展函数
fscript 是 AWTK 内置的脚本引擎,开发者可以在 UI XML 文件中直接嵌入 fscript 脚本,提高开发效率。本文介绍一下 fscript 中的 ** JSON 扩展函数 ** 1.json_load 加载 json 数据。 原型 json_load(str) > object json_load(binary) > object js…...
动态规划 —— dp 问题-买卖股票的最佳时机III
1. 买卖股票的最佳时机III 题目链接: 123. 买卖股票的最佳时机 III - 力扣(LeetCode)https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iii/description/ 2. 题目解析 3. 算法原理 状态表示:以某一个位置为结尾或者…...
“绽放艺术风采、激发强国力量” 海南省第十一届中小学生艺术展演活动圆满开展
2024年11月1日,由省教育厅主办、琼台师范学院承办的海南省第十一届中小学生艺术展演省级展演活动在海口正式拉开帷幕。来自全省各市县、省属学校等共计4000余名师生参加本届中小学生艺术展演现场展演活动。 本届展演活动以“绽放艺术风采、激发强国力量”为主题&…...
Linux之文件和目录类命令详解(2)
Linux之文件和目录类命令详解(2) 1、mv-移动文件或重命名2、find-查找文件和目录3、locate-快速查找文件4、du-显示目录或文件的磁盘使用情况5、df-显示文件系统的磁盘空间使用情况6、chmod-更改文件或目录的权限7、chown-更改文件或目录的拥有者8、tree…...
NVR管理平台EasyNVR多品牌NVR管理工具/设备摄像头开启ONVIF的方法
NVR小程序接入平台EasyNVR作为一款功能强大的安防视频监控平台,以其出色的兼容性和灵活性,在智慧校园、智慧工厂、智慧水利等多个场景中得到了广泛应用。本文将重点介绍如何为大华摄像头开启ONVIF协议,以便与EasyNVR进行无缝对接。 大华大部分…...
Pr 视频过渡:沉浸式视频
效果面板/视频过渡/沉浸式视频 Video Transitions/Immersive Video Adobe Premiere Pro 的视频过渡效果中,沉浸式视频 Immersive Video效果组主要用于 VR 视频剪辑之间的过渡。 自动 VR 属性 Auto VR Properties是所有 VR 视频过渡效果的通用选项。 默认勾选&#x…...
SwiftUI开发教程系列 - 第1章:简介与环境配置
1.1 SwiftUI简介 SwiftUI 是 Apple 于 2019 年推出的声明式用户界面框架,旨在简化 iOS、macOS、watchOS 和 tvOS 应用的 UI 开发。与 UIKit 的命令式编程方式不同,SwiftUI 提供了一种声明式语法,让开发者可以以更加直观、简洁的方式构建 UI。…...
gitlab ci/cd搭建及使用笔记
记录下使用gitlab的ci/cd的devops构建过程中,一些易忘点或者踩坑点: 官方文档中英文(建议英文) https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html https://gitlab.cn/docs/jh/ci/pipelines/schedules.html为什么创建了…...
Xcode 16 中 Swift Testing 的参数化(Parameterized)机制趣谈
概述 我们之前曾在 《用接地气的例子趣谈 WWDC 24 全新的 Swift Testing 入门》系列博文以及《WWDC24(Xcode 16)中全新的 Swift Testing 使用进阶》博文中较为系统地介绍了今年 WWDC 24 中全新的 Swift Testing 测试系统。 不过 Swift Testing 的本领远…...
Python自动化运维DevSecOps与安全自动化
Python自动化运维DevSecOps与安全自动化 目录 🛡️ DevSecOps概念与实践🔍 自动化安全扫描与漏洞修复🧰 基于Python的安全审计与合规性检查🐳 云平台与容器安全:基于Python的容器扫描工具⚠️ 自定义安全检测与漏洞修…...
2024下半年系统架构师考试【回忆版】
2024年11月10日,系统架构师考试如期举行,屡战屡败的参试倒是把北京的学校转了好几所。 本次考试时间 考试科目考试时间综合知识、案例分析8:30 - 12:30论文14:30 - 16:30 综合知识 1、1-1000以内包含5的数字个数 2、 案例分析 1、RESTful 对于前后…...
UE5.4 PCG 自定义PCG蓝图节点
ExecuteWithContext: PointLoopBody: 效果:点密度值与缩放成正比...
迁移学习相关基础
迁移学习 目标 将某个领域或任务上学习到的知识或模式应用到不同但相关的领域或问题中。 主要思想 从相关领域中迁移标注数据或者知识结构、完成或改进目标领域或任务的学习效果。 概述 Target data:和你的任务有直接关系的数据,但数据量少ÿ…...
大型门户网站建设报价表/网络营销和传统营销的区别
前言 Spring 5 于 2017 年 9 月发布了通用版本 (GA),它标志着自 2013 年 12 月以来第一个主要 Spring Framework 版本。它提供了一些人们期待已久的改进,还采用了一种全新的编程范例,以反应式宣言中陈述的反应式原则为基础。几天前小编从朋友…...
古腾堡 主题 wordpress/seo收费还是免费
选择排序概念 选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻…...
备案 网站建设方案书怎么写/网上推广怎么做
Kotlin Coroutines(协程) 完全解析系列:本文基于 Kotlin v1.3.0-rc-146,Kotlin-Coroutines v1.0.0-RC1前面一篇文章协程简介,简单介绍了协程的一些基本概念以及其简化异步编程的优势,但是协程与线程有什么区别,协程的挂…...
wordpress建设网站的方法/商城网站开发公司
目录 项目打包 项目本地预览 打包体积分析 生产环境优化 路由懒加载 去掉console 配置CDN 项目打包 通过命令对项目进行打包 在项目根目录打开终端,输入打包命令:npm run build 等待打包完成,打包后的内容被放在项目根下的 build 文件夹中…...
企业网站的建设论文/给我免费的视频在线观看
实验结论 一、实验一:成在屏幕上输出内存单元中的十进制两位数 1、源代码 1 ; 在屏幕上输出内存单元中的十进制两位数2 assume cs:code, ds:data3 data segment4 db 125 db ?,? ; 前一个字节用于保存商,后一个字节用于保存余数6 data ends…...
嘉善县住房和城乡规划建设局网站/竞价托管推广多少钱
https://blog.csdn.net/u012867916/article/details/77430393...