外贸企业公司网站建设/宁波百度seo点击软件
✨个人主页: Yohifo
🎉所属专栏: C++修行之路
🎊每篇一句: 图片来源
- The power of imagination makes us infinite.
- 想象力的力量使我们无限。
文章目录
- 📘前言
- 📘正文
- 1、默认成员函数
- 1.1、默认构造
- 1.2、拷贝构造
- 1.3、析构函数
- 1.4、赋值重载
- 2、迭代器
- 2.1、正向迭代器
- 2.2、反向迭代器
- 3、容量相关
- 3.1、大小、容量、判空
- 3.2、空间扩容
- 3.3、大小调整
- 3.4、缩容
- 4、数据访问相关
- 4.1、下标随机访问
- 4.2、首尾元素
- 5、数据修改相关
- 5.1、尾插尾删
- 5.2、任意位置插入删除
- 5.3、交换、清理
- 6、相关试题
- 📘总结
📘前言
vector
是表示可变大小数组的序列 容器
,其使用的是一块 连续 的空间,因为是动态增长的数组,所以 vector
在空间不够时会扩容;vector
优点之一是支持 下标的随机访问,缺点也很明显,头插或中部插入效率很低,这和我们之前学过的 顺序表
性质很像,不过在结构设计上,两者是截然不同的
📘正文
本文介绍的是 vector 部分常用接口
1、默认成员函数
vector
的成员变量如上图所示,就是三个指针,分别指向:
_start
指向空间起始位置,即begin()
_finish
指向最后一个有效元素的下一个位置,相当于end()
_end_of_storage
指向已开辟空间的终止位置
1.1、默认构造
vector
支持三种默认构造方式
- 默认构造大小为
0
的对象 - 构造
n
个元素值为val
的对象 - 通过迭代器区间构造,此时元素为自定义类型,如
string
、vector
、Date
等
int main()
{vector<int> v1; //构造元素值为 int 的对象vector<char> v2(10, 'x'); //构造10个值为'x'的对象string s = "abcedfg";vector<char> v3(s.begin(), s.end()); //构造 s 区间内的元素对象return 0;
}
注:也可以直接通过 vector<int> v4 = {1, 2, 3}
的方式构造对象,不过此时调用了 拷贝构造
函数
vector<int> v4 = {1, 2, 3}; //这种构造方式比较常用,有点像数组赋初始值
1.2、拷贝构造
拷贝构造
:将对象 x
拷贝、构造出新对象 v
,拷贝构造
函数的使用方法很简单,利用一个已经存在的 vector
对象,创建出一个值相同的对象
vector<int> x = { 1,2,3,4,5 };vector<int> v(x); //利用对象 x 构造出 v
可以看到,对象 v
和对象 x
的值是一样的(copy)
注意: 调用拷贝构造时,两个对象类型需匹配,且被复制对象需存在
拷贝构造
和 赋值重载
有 深度拷贝
的讲究,在模拟实现 vector
时演示
1.3、析构函数
析构函数,释放动态开辟的空间,因为 vector
使用的空间是连续的,所以释放时直接通过 delete[] _start
释放即可
析构函数
会在对象生命周期 结束时自动调用,平常在使用时无需关心
// ~vector 函数内部
delete[] _start;
_start = _finish = _end_of_storage = nullptr;
1.4、赋值重载
拷贝构造
的目的是创建一个新对象,赋值重载
则是对一个老对象的值进行 改写
int arr[] = { 6,6,8 };
vector<int> v1(arr, arr + (sizeof(arr) / sizeof(arr[0]))); //迭代器区间构造vector<int> v2; //创建一个空对象
v2 = v1; //将 v1 的值赋给老对象 v2
注意: v1
对象赋值给 v2
对象后,v1
本身并不受任何影响,改变的只是 v2
赋值重载
函数有返回值,适用于多次赋值的情况
vector<int> v3 = { 9,9,9 };
v2 = v1 = v3; //这样也是合法的,最终 v1、v2 都会受到影响
2、迭代器
迭代器
是一个天才设计,它的出现使得各种各样的容器都能以同一种方式进行 访问
、遍历
数据
vector
支持下标随机访问, 所以大多数情况下访问数据都是使用下标,但 迭代器
相关接口它还是有的
vector
和 string
的 迭代器
本质上就是原生指针,比较简单,但后续容器的 迭代器
就比较复杂了
复杂归复杂,但每种 容器
的迭代器使用方法都差不多,这就是 迭代器
设计的绝妙之处
注:string
和 vector
的迭代器都是 随机迭代器(RandomAccessIterator),可以随意走动,支持全局排序函数 sort
2.1、正向迭代器
正向迭代器即 从前往后 遍历的 迭代器
利用迭代器正向遍历 vector
对象
const char* ps = "Hello Iterator!";
vector<char> v(ps, ps + strlen(ps)); //迭代器构造vector<char>::iterator it = v.begin(); //创建该类型的迭代器while (it != v.end())
{cout << *it;it++;
}
cout << endl;
注意:
- 迭代器在创建时,一定要先写出对应的类型,如
vector<int>
,嫌麻烦可以直接用auto
推导 - 在使用迭代器遍历时,结束条件为
it != v.end()
不能写成<
,因为对于后续容器来说,它们的空间不是连续的,判断小于无意义 - begin() 为第一个有效元素地址,end() 为最后一个有效元素的下一个地址
vector
是 随机迭代器,也支持这样玩
//auto 根据后面的类型,自动推导迭代器类型
auto it = v.begin() + 3; //这是随机的含义
2.2、反向迭代器
反向迭代器常用来 反向遍历(从后往前)容器
反向遍历 vector
对象
const char* ps = "Hello ReverseIterator!";
vector<char> v(ps, ps + strlen(ps));vector<char>::reverse_iterator it = v.rbegin(); //创建该类型的迭代器while (it != v.rend())
{cout << *it;it++;
}
cout << endl;
反向迭代器的注意点与正向迭代器一致,值得注意的是 rbegin()
和 rend()
begin()
和 end()
适用于 正向迭代器
begin()
为对象中的首个有效元素地址end()
为对象中最后一个有效元素的下一个地址
rbegin()
和 rend()
适用于 反向迭代器
rbegin()
为对象中最后一个有效元素地址rend()
为对象中首个有效元素的上一个地址
注意: begin()
不能和 rend()
混用
上述 迭代器 都是用于正常 可修改 的对象,对于 const
对象,还有 cbegin()
、cend()
和 crbegin()
、crend()
,当然这些都是 C++11
中新增的语法
注:对于
const
对象,存在重载版本,如begin() const
,也就是说,const
修饰的对象也能正常使用begin()
、end()
、rbegin()
和rend()
;C++11
中的这个新语法完全没必要,可以不用,但不能看不懂
3、容量相关
下面来看看 vector
容量相关函数和扩容机制
3.1、大小、容量、判空
大小 size()
容量 capacity()
判空 empty()
这些函数对于我们太熟悉了,和 顺序表
的一模一样
直接拿来用一用
vector<int> v = { 1,2,3,4,5 };
cout << "size:" << v.size() << endl;
cout << "capacity:" << v.capacity() << endl;
cout << "empty:" << v.empty() << endl;
这几个函数都是直接拿来用的,没什么值得注意的地方
3.2、空间扩容
连续空间可扩容,像 string
一样,vector
也有一个提前扩容的函数:reserve()
输入指定容量即可扩容,常用来 提前扩容,避免因频繁扩容而导致的内存碎片
下面来通过一个小程序先来简单看看 PJ
版 和 SGI
版的 默认扩容机制
vector<int> v;
size_t capacity = v.capacity();
cout << "Default capacity:" << capacity << endl;int i = 0;
while (i < 100)
{v.push_back(i); //尾插元素 i//如果不相等,证明出现扩容if (capacity != v.capacity()){capacity = v.capacity();cout << "New capacity:" << capacity << endl;}i++;
}
可以看出,PJ
版采用的是 1.5
倍扩容法,而 SGI
版直接采用 2
倍扩容法,待扩容量较小时,PJ
版会扩容更多次,浪费更多空间;但待扩容量越大时,变成 SGI
版浪费更多空间,总的来说,两种扩容方式各有各的优点
如果我们提前知道待扩容空间大小 n
,可以直接使用 reserve(n)
的方式进行 提前扩容,这样一来,无论是哪种版本,最终容量大小都是一致的,且不会造成空间浪费
v.reserve(100); //提前开辟空间
此时是非常节约空间的,而且不会造成很多的内存碎片
注意: 当 n
小于等于 capacity()
时,reserve
函数不会进行操作
3.3、大小调整
与提前扩容相似的大小调整,主要调整的是 _finish
在扩容的同时对新空间进行初始化,参数2 val
为缺省值,缺省为对应对象的默认构造值
- 自定义类型也有默认构造函数,如
int()
,构造后为0
- 这种构造方法称为
匿名构造
,后续会经常简单(很方便)
vector<int> v1;
v1.resize(10); //使用缺省值vector<int> v2;
v2.resize(10, 6); //使用指定值
区别在于:是否指定初始化值
resize
和 reserve
:
- 两者的共同点是都能起到扩容的效果
resize
扩容的同时还能进行初始化,reserve
则不能resize
会改变_finish
,而reserve
不会- 对于两者来说,当 n 小于等于 capacity() 时,都不进行扩容操作
resize
此时会初始化size()
至capacity()
这段空间
3.4、缩容
vector
中还提供一个了缩容函数,将原有容量缩小,但这完全没必要,以下是缩容步骤:
- 开辟新空间(比原空间更小的空间)
- 用原空间中的数据将新空间填满,超出部分丢弃
- 释放原空间,完成缩容
为了一个缩容而导致的是代价是很大的,因此 不推荐缩容,想要改变 size()
时,可以使用 resize
函数
这里就不演示这个函数了,就连官方文档上都有一个 警告标志
4、数据访问相关
连续空间数据访问时,可以通过 迭代器
,也可以通过 下标
,这里还是更推荐使用 下标
,因为很方便;作为 “顺序表”,当然也支持访问首尾元素
4.1、下标随机访问
下标访问是通过 operator[]
运算符重载实现的
库中提供了两个重载版本,用以匹配普通对象和 const
对象
const char* ps = "Hello";
vector<char> v(ps, ps + strlen(ps)); //迭代器区间构造
const vector<char> cv(ps, ps + strlen(ps)); //迭代器区间构造size_t pos = 0; //下标
while (pos < v.size())
{cout << v[pos]; //普通对象cout << cv[pos]; //const 对象pos++;
}
cout << endl;
除了 operator[]
以外,库中还提供了一个 at
函数,实际就是对 operator[]
的封装
v.at(0);
v[0] //两者是完全等价的
注意: 因为是下标随机访问,所以要小心,不要出现 越界 行为
4.2、首尾元素
front()
获取首元素,back()
获取尾元素
vector<int> v = { 1,1,1,0,0,0 };
cout << "Front:" << v.front() << endl;
cout << "Back:" << v.back() << endl;
实际上,front()
就是返回 *_start
,back()
则是返回 *_finish
5、数据修改相关
vector
也可以随意修改其中的数据,比如尾部操作,也支持任意位置操作,除此之外,还能交换两个对象,亦或是清除对象中的有效元素
5.1、尾插尾删
push_back()
和 pop_back()
算是老相识了,两个都是直接在 _finish
上进行操作
这两个函数操作都很简单,不再演示
注意: 如果对象为空,是不能尾删数据的
对于已有对象数据的修改,除了赋值重载外,还有一个函数 assign()
,可以重写指定对象中的内容,使用方法很像默认构造函数,但其本质又和赋值重载一样
第一种方式是通过迭代器区间赋值,第二种是指定元素数和元素值赋值
5.2、任意位置插入删除
任意位置插入删除是使用 vector
的重点,因为这里会涉及一个问题:迭代器失效,这个问题很经典,具体什么原因和如何解决,将在模拟实现 vector
中解答
简单演示一下用法:
int arr[] = { 6,6,6 };
vector<int> v = { 1,0 };//在指定位置插入一个值
v.insert(find(v.begin(), v.end(), 1), 10); //10,1,0//在指定位置插入 n 个值
v.insert(find(v.begin(), v.end(), 0), 2, 8); //10,1,8,8,0//在指定位置插入一段迭代器区间
v.insert(find(v.begin(), v.end(), 8), arr, arr + (sizeof(arr) / sizeof(arr[0]))); //10,1,6,6,6,8,8,0//删除指定位置的元素
v.erase(find(v.begin(), v.end(), 10)); //1,6,6,6,8,8,0//删除一段区间
v.erase(v.begin() + 1, v.end()); //1
先浅浅演示一下 迭代器失效的场景
vector<int> v = { 1,2,3 };
auto it = v.end(); //利用迭代器模拟尾插for (int i = 0; i < 5; i++)
{v.insert(it, 10);it++; //再次使用迭代器i++;
}
运行(调试模式下)结果是这样的:
不止 insert
的迭代器会失效,erase
的迭代器也会失效
简单来说:插入或删除后,可能导致迭代器指向位置失效,此时没有及时更新,再次使用视为非法行为
因此我们认为 vector
在插入或删除后,迭代器失效,不能再使用,尤其是 PJ
版本,对迭代器失效的检查十分严格
至于其具体原因和方法,留在下篇文章中揭晓
5.3、交换、清理
还剩下两个简单函数,简单介绍下就行了
vector<int> v1 = { 1,2,3 };
vector<int> v2 = { 4,5,6 };v1.swap(v2); //交换两个对象v1.clear();
v2.clear(); //清理
std
中已经提供了全局的 swap
函数,为何还要再提供一个呢?
- 这个函数实现原理不同
std::swap
,std::swap
实际在交换时,需要调用多次拷贝构造和赋值重载函数,对于深拷贝来说,效率是很低的 - 而
vector::swap
在交换时,交换是三个成员变量,因为都是指针,所以只需要三次浅拷贝交换,就能完美完成任务 - 实际在
vector::swap
内部,还是调用了std::swap
,不过此时是高效的浅拷贝
至于 clear
函数,实现很简单:
- 令
_finish
等于_start
,就完成了清理,不需要进行缩容,这样做是低效的
关于 vector
更多、更详细的内容,欢迎移步 《C++ STL学习之【vector的模拟实现】》
6、相关试题
光知道怎么使用是不够的,还需要将知识付诸于实践,切记纸上谈兵
下面是一些比较适合练习使用 vector
的试题,可以做做
vector 值得做的题目
📘总结
以上就是本次关于 STL
之 vector
的全部讲解了,vector
相对来说函数比较少,也比较好理解,不过在实际使用中,会存在不少问题,需要对 vector
的不断使用以提高认知,如果对 vector
剩余函数感兴趣,可以阅读官方文档 vector
如果你觉得本文写的还不错的话,可以留下一个小小的赞👍,你的支持是我分享的最大动力!
如果本文有不足或错误的地方,随时欢迎指出,我会在第一时间改正
相关文章推荐
STL 之 string 类
C++ STL学习之【string类的模拟实现】
C++ STL 学习之【string】
===============
内存、模板
C++【模板初阶】
C/C++【内存管理】
===============
类和对象实操
类和对象实操之【日期类】
![]()
相关文章:

C++ STL学习之【vector的使用】
✨个人主页: Yohifo 🎉所属专栏: C修行之路 🎊每篇一句: 图片来源 The power of imagination makes us infinite. 想象力的力量使我们无限。 文章目录📘前言📘正文1、默认成员函数1.1、默认构造…...

方差分析与单因素方差分析
研究分类型自变量对数值型因变量的影响。检验统计的设定和检验方法与变量间的方差是否相等有关。 例如研究行业、服务等级对投诉数的影响:如表格中给出4个行业、每个行业有3个服务等级、样本容量为7、观测值为投诉数。则构成一个3维的矩阵。 在上述基础上…...

分布式链路追踪组件skywalking介绍
SkyWalking组件概念 一个开源的可观测平台, 用于从服务和云原生基础设施收集, 分析, 聚合及可视化数据。SkyWalking 提供了一种简便的方式来清晰地观测分布式系统, 甚至横跨多个云平台。SkyWalking 更是一个现代化的应用程序性能监控(Application Performance Monitoring)系统…...

SUBMIT的用法
SUBMIT的用法 一、简介 系统MB52/MB51/MB5B等类似的报表 ,虽然数据很全面,执行效率也够快,但是经常会不满足用户需求(增添字段、添加查询条件等),很多ABAP 会选择去COPY出标准程序,然后去做修改…...

网页基本标签、图像标签、链接标签、块内元素和块元素、列表标签、表格标签
一、网页基本标签 标题标签 段落标签 未写段落标签前,文本没有按照想要的格式排列显示 写段落标签后: 每句都是一段,所以句与句距离比较宽 换行标签 同一段,只是把文字换行,所以比较紧凑 水平线标签 字体样式标签 …...

RxJava操作符变换过程
要使用Rxjava首先要导入两个包,其中rxandroid是rxjava在android中的扩展 implementation io.reactivex:rxandroid:1.2.1implementation io.reactivex:rxjava:1.2.0我们在使用rxjava的操作符时都觉得很方便,但是rxjava是怎么实现操作符的转换呢࿰…...

开放平台订单接口
custom-自定义API操作 注册开通 taobao.custom 公共参数 名称 类型 必须 描述 key String 是 调用key(必须以GET方式拼接在URL中) secret String 是 调用密钥 api_name String 是 API接口名称(包括在请求地址中&a…...

CDN相关知识点
1、什么是CDN?CDN的作用是什么? CDN(Content Delivery Network,内容分发网络)是一种通过在多个节点上分布内容以提高网络性能、可靠性和可扩展性的网络解决方案。CDN通过在不同的地理位置部署服务器,使用户…...

【论文阅读】注意力机制与二维 TSP 问题
前置知识 注意力机制 见 这篇 二维 TSP 问题 给定二维平面上 nnn 个点的坐标 S{xi}i1nS\{x_i\}_{i1}^nS{xi}i1n,其中 xi∈[0,1]2x_i\in [0,1]^2xi∈[0,1]2,要找到一个 1∼n1\sim n1∼n 的排列 π\piπ ,使得目标函数 L(π∣s)∥xπ…...

[深入理解SSD系列 闪存实战2.1.7] NAND FLASH基本编程(写)操作及原理_NAND FLASH Program Operation 源码实现
前言 上面是我使用的NAND FLASH的硬件原理图,面对这些引脚,很难明白他们是什么含义, 下面先来个热身: 问1. 原理图上NAND FLASH只有数据线,怎么传输地址? 答1.在DATA0~DATA7上既传输数据,又传输地址 当ALE为高电平时传输的是地址, 问2. 从N...

PMP项目管理项目资源管理
目录1 项目资源管理概述2 规划资源管理3 估算活动资源4 获取资源5 建设团队6 管理团队7 控制资源1 项目资源管理概述 项目资源管理包括识别、获取和管理所需资源以成功完成项目的各个过程,这些过程有助于确保项目经理和项目团队在正确的时间和地点使用正确的资源。…...

程序的编译和链接
程序的编译和链接程序的编译和链接程序的两种环境翻译环境详解编译和链接预处理编译汇编链接运行环境程序的编译和链接 程序的两种环境 在ANSI C的任何一种实现中,存在两个不同的环境。 第1种是翻译环境,在这个环境中源代码被转换为可执行的机器指令。 …...

Win11的两个实用技巧系列之无法联网怎么办、耳机没声音的多种解决办法
Win11无法联网怎么办? win11安装后设备不能上网的解决办法Win11无法联网怎么办?电脑安装win11系统以后,发现不能上网,连接不上网络,该怎么办呢?下面我们就来看看win11安装后设备不能上网的解决办法Win11安装后&#x…...

【微信小程序】-- 自定义组件 - 数据监听器 - 案例 (三十五)
💌 所属专栏:【微信小程序开发教程】 😀 作 者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &…...
Linux - 第7节 - 进程间通信
1.进程间通信介绍 进程间通信目的: 数据传输:一个进程需要将它的数据发送给另一个进程 。 资源共享:多个进程之间共享同样的资源。 通知事件:一个进程需要向另一个或一组进程发送消息,通…...

# 数据完整性算法在shell及python中的实践
数据完整性算法在shell及python中的实践 文章目录数据完整性算法在shell及python中的实践1 预备知识1.1 摘要算法1.2 报文(数据)完整性校验1.3 python byte类型字符串与普通字符串区别2 传统方法(散列函数)2.1 在shell中实践2.2 在…...

QEMU启动x86-Linux内核
目录QEMU简介linux启动流程我的环境安装QEMU软件包安装源码安装编译linux内核编译busybox制作initramfs使用QEMU启动linux内核简化命令参考QEMU简介 QEMU(quick emulator)是一个通用的、开源的硬件模拟器,可以模拟不同硬件架构(如…...

C/C++每日一练(20230311)
目录 1. 计算阶乘的和 ★ 2. 基本计算器 ★★★ 3. N皇后 II ★★★ 🌟 每日一练刷题专栏 C/C 每日一练 专栏 Python 每日一练 专栏 1. 计算阶乘的和 计算:1!-2!3!-4!5!-6!7!-8!9!-10!,并输出计算结果。 注意:不全是…...

哪个牌子的洗地机耐用?耐用的洗地机推荐
作为当下非常热销的洗地机,它不仅解放了双手,使用也非常的便捷。是生活品质提高的最好代表,但是面对市面上让人眼花缭乱的洗地机,挑选几个来回都决定不了到底入手哪个好!为了能帮助大家选购到合适的洗地机,…...

搭建一个中心化的定时服务
1. 背景 在物联网络,很多设备之间都在进行交互,其中云端在远程交流中起到了很重要的作用。比如,一台设备想进行调温,但是需要知道此时房间的温度,那就需要定时去查询传感器测出来的房间温度,如果温度过高&a…...

【CSS】快速入门笔记
视频链接:https://www.bilibili.com/video/BV1mS4y1Z7Ga/?spm_id_from333.999.0.0&vd_source1ad00d913eae8281cbadad6ae66fb06c 文章目录一、CSS语法1.结构2.样式类型1)内联样式 Inline Style2)内部样式 Internal Style3)外部…...

第161篇 笔记-去中心化的含义
本文主要内容来自Vitalik Buterin的文章。“去中心化”这个词是在加密经济学领域用得最多的一个词,通常也作为辨别区块链的依据。然而,这个词也可能是被定义得最不恰当的一个词。数千小时的研究和价值数十亿美元哈希算力的投入都旨在实现去中心化&#x…...

「计算机组成原理」数据的表示和运算(二)
文章目录五、奇偶校验码六、算术逻辑单元ALU6.1 电路的基本原理6.2 加法器的设计6.2.1 一位全加器6.2.2 串行加法器6.2.3 串行进位的并行加法器6.2.4 并行进位的并行加法器七、补码加减运算器八、标志位的生成九、定点数的移位运算9.1 算数移位9.2 逻辑移位9.3 循环移位五、奇偶…...

建立自己的博客
环境安装: w10系统安装 第一步:安装git Git 官网: https://git-scm.com/ 第二步:安装Node.js Node.js官网:https://nodejs.org/zh-cn/ 使用cmd检测: node -v 第三步:安装Hexo Hexo官网:htt…...

Docker 安装mysql Mac 环境下
已安装桌面端 Docker (Mac安装Docker) 安装方式一 打开链接 https://www.docker.com/products/docker-desktop 选择平台下载 安装方式二 安装homebrew /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/m…...

《C++代码分析》第三回:类成员函数覆盖父类函数的调用(分析this指针的变化)
一、前言 在C的学习中我们知道,子类是可以覆盖父类的方法,这里我们探讨一下子类方法调用父类方法时this指针时如何变化的。 二、示例代码 #include "windows.h" #include "windef.h" #include <iostream> #include <tch…...

Altium designer--软件简介及安装教程(Altium designer16)
一、软件介绍(完整安装包资源见文末链接,含破解license) Altium Designer 是一款简单易用、原生3D设计增强的一体化设计环境,结合了原理图、ECAD库、规则和限制条件、BoM、供应链管理、ECO流程和世界一流的PCB设计工具。通过原理…...

Windows系统下基于开源软件的多物理场仿真
Windows系统下基于开源软件的多物理场仿真实践技术应用随着计算机技术的发展,计算机仿真技术日益成为继实验和理论之后的第三种重要研究和设计手段。真实世界中遇到的问题往往是固体力学,流体力学,热,电磁等多种现象耦合而成&…...

【STL】list剖析及模拟实现
✍作者:阿润菜菜 📖专栏:C 初识list 1. list基本概况 list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立…...

Go打包附件内容到执行文件
前言 如果我们的应用在启动的时候需要对数据库进行初始化(比如建表等), 可以通过读取.sql文件内容直接执行. 但是, 这样会带出一个问题: 在发送可执行文件的时候, 需要连带着附件文件, 并且相对路径还不能出错. 这样太麻烦了有时我们并不希望附件的内容被使用者看到 处于种种…...