《C++ Primer》 第十二章 动态内存
《C++ Primer》 第十二章 动态内存
动态内存与智能指针
shared_ptr允许多个指针指向同一个对象;unique_ptr则“独占”所指向的对象,weak_ptr指向shared_ptr所管理的对象。这三种类型都定义在memory头文件中。
shared_ptr类:默认初始化的智能指针中保存着一个空指针。
shared_ptr<string> p1; //shared_ptr,可以指向string
shared_ptr<list<int>> p2; //shared_ptr, 可以指向int的list//如果p1不为空,检测它是否指向一个空string
if(p1 && p1->empty())*p1 = "hi";//如果p1指向一个空string,解引用p1,将一个新值赋予string
make_shared函数:在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。定义在memory中。
//指向一个值为42的int的shared_ptr
shared_ptr<int> p3 = make_shared<int> (42);
//p4指向一个值为"999999999"的string
shared_ptr<string> p4 = make_shared<string> (10,'9');
//p5指向一个值初始化的int,即值为0
shared_ptr<int> p5 = make_shared<int>();
//通常使用auto定义一个对象来保存make_shared的结果
//p6指向一个动态分配的空vector<string>
auto p6 = make_shared<vector<string>>();
shared_ptr的拷贝和构造:
auto p = make_shared<int>(42);//p指向的对象只有一个引用者
auto q(p);//p和q指向相同对象,此对象有两个引用者
定义StrBlob类:
class StrBlob{
public:typedef std::vector<std::string>::size_type size_type;StrBlob();StrBlob(std::initializer_list<std::string> i1);size_type size() const { return data->size(); }bool empty() const { return data->empty(); }//添加和删除元素void push_back(const std::string &t) { data->push_back(t); }void pop_back();//元素访问std::string& front();std::string& back();
private:std::shared_ptr<std::vector<std::string>> data;//如果data[i]不合法,抛出一个异常void check(size_type i, const std::string &msg) const;
};
元素访问成员函数:
void StrBlob::check(size_type i, const string &msg) const
{if(i>=data->size())throw out_of_range(msg);
}string& StrBlob::front()
{//如果vector为空,check会抛出一个异常check(0, "front on empty StrBlob");
}string& StrBlob::back()
{check(0, "back on empty StrBlob");return data->back();
}void StrBlob::pop_back()
{check(0, "pop_back on empty StrBlob");data->pop_back();
}
直接管理内存:运算符new分配内存,delete释放new分配的内存。
使用new动态分配和初始化对象:new返回一个指向该对象的指针
int *pi = new int; //pi指向一个动态分配、并返回该对象的指针string *ps = new string;//初始化为空string
int *pi = new int;//pi指向一个未初始化的intint *pi = new int(1024);//pi指向的对象的值是1024
string *ps = new string(10,'9'); //*ps为“999999999”//vector有10个元素,值依次从0~9
vector<int> *pv = new vector<int> {0,1,2,3,4,5,6,7,8,9};string *ps1 = new string;//默认初始化为空string
string *ps = new string();//值初始化为空string
int *pi1 = new int; //默认初始化;*pi1的值未定义
int *pi2 = new int();//值初始化为0;*pi2为0auto p1 = new auto(obj); //p指向一个与obj类型相同的对象,该对象用obj进行初始化
auto p2 = new auto{a,b,c};//错误:括号中只能有单个初始化器
动态分配的const对象:用new分配const对象是合法的:
//分配并初始化一个const int
const int *pci = new const int(1024);
//分配并默认初始化一个const的空string
const string *pcs = new const string;
内存耗尽:
//如果分配失败,new返回一个空指针
int *p1 = new int;//如果分配失败,new抛出std::bad_alloc
int *p2 = new (nothrow) int;//如果分配失败,new返回一个空指针
释放动态内存:销毁给定的指针指向的对象;释放对应的内存。
delete p;//p必须指向一个动态分配的对象或是一个空指针
指针值和delete:传递给delete的指针必须指向动态分配的内存,或者是一个空指针。
int i, *pi1 = &i, &pi2 = nullptr;
double *pd = new double(33), *pd2 = pd;
delete i;//错误:i不是一个指针
delete pi1;//未定义:pi1指向一个局部变量
delete pd;//正确
delete pd2;//未定义:pd2指向的内存已经被释放掉了
delete pi2;//正确:释放一个空指针总是没有错误的const int *pci = new const int(1024);
delete pci;//正确:释放一个const对象
动态对象的生存期直到被释放时为止:
//factory返回一个指针,指向一个动态分配的对象
Foo* factory(T arg)
{//视情况处理argreturn new Foo(arg);//调用者负责释放此内存
}void use_factory(T arg)
{Foo *p = factory(arg);//使用p但不delete它
}//p离开了它的作用域,但它所指向的内存没有被释放!!!void use_factory(T arg)
{Foo *p = factory(arg);//使用pdelete p;//现在记得释放内存,我们已经不需要它了
}Foo* use_factory(T arg)
{Foo *p = factory(arg);//使用preturn p;//调用者必须释放内存
}
提供优先的保护:动态内存的一个基本问题是可能有多个指针指向相同的内存。
int *p (new int(42));//p指向动态内存
auto q = p; //p和q指向相同的内存
delete p; //p和q均变为无效
p = nullptr; //指出p不再绑定到任何对象
shared_ptr和new结合使用:
shared_ptr<double> p1;//shared_ptr可以指向一个double
shared_ptr<int> p2(new int(42));//p2指向一个值为42的int//不能将一个内置指针隐式转换为一个智能指针
shared_ptr<int> p1 = new int(1024);//错误:必须使用直接初始化形式
shared_ptr<int> p2(new int(1024));//正确:使用了直接初始化形
不能进行内置指针到智能指针间的隐式转换。一个返回shared_ptr的函数不能在其返回语句中隐式转换为一个普通指针:
shared_ptr<int> clone(int p){return new int(p);//错误:隐式转换为shared_ptr<int>
}//必须将shared_ptr显式绑定到一个想要返回的指针上
shared_ptr<int> clone(int p){//正确:显示地用int*创建shared_ptr<int>return shared_ptr<int>(new int(p));
}
不要混合使用普通指针和智能指针;也不要使用get初始化另一个智能指针或为智能指针赋值。
shared_ptr<int> p(new int(42));//引用计数为1
int *q = p.get();//正确,但使用q时要注意,不要让它管理的指针被释放
{//新程序块
//未定义:两个独立的shared_prt指向相同的内存shared_ptr<int>(q);
}//程序块结束,q被销毁,它指向的内存本释放
int foo = *p; //未定义:p指向的内存已经被释放了
其它shared_ptr操作:
p = new int(1024); //错误:不能将一个指针赋予shared_ptr
p.reset(new int(1024)); //正确:p指向一个新对象if(!p.unique())p.reset(new string(*p));//我们不是唯一用户;分配新的拷贝
*p += newVal;
智能指针和异常:
void f()
{shared_ptr<int> sp(new int(42));//分配一个新对象//这段代码抛出一个异常,且在f中未被捕获
}//在函数结束时shared_ptr自动释放内存void f()
{int *p = new int(42);//动态分配一个新对象//这段代码抛出一个异常,且在f中未被捕获delete ip;//退出之前释放内存
}
智能指针和哑类“
struct destination;//表示我们正在连接什么
struct connection;//使用连接所需的信息
connection connect(destination*);//打开连接
void disconnect(connection);//关闭给定的连接
void f(destination &d)
{//获得一个连接;记住使用玩后要关闭它connection c = connect(&d);//使用连接//如果我们在f退出之前忘记调用disconnect,就无法关闭c了
}//在创建shared_ptr时,可以传递一个可选的指向删除器函数的参数
void f(destination &d)
{//获得一个连接;记住使用玩后要关闭它connection c = connect(&d);shared_ptr<connection> p(&c, end_connection);//使用连接//如果我们在f退出之前忘记调用disconnect,就无法关闭c了
}
unique_ptr:与shared_ptr不同,某个时刻只能有一个unique_ptr指向一个给定对侠女。当unique_ptr被销毁时,它所指向的对象也被销毁。
unique_ptr<double> p1;//可以指向一个douvbble的unique_ptr
unique_ptr<int> p2(new int(42));//p2指向一个值为42的int
//由于一个unique_ptr拥有它指向的对象,因此unique_ptr不支持普通的拷贝或赋值操作
unique_ptr<string> p1(new string("Stegosaurus"));
unique_ptr<string> p2(p1);//错误:unique_ptr不支持拷贝
unique_ptr<string> p3;
p3 = p1;//错误:unique_ptr不支持赋值
使用unique_ptr参数和返回unique_ptr
unique_ptr<int> clone(int p){//正确:从int*创建一个unique_ptr<int>return unique_ptr<int> (new int(p));
}
//还可以返回一个局部对象的拷贝
unique_ptr<int> clone(int p){unique_ptr<int> ret(new int(p));//...return ret;
}
weak_ptr:是一种不控制所指向对象生存期的智能指针,它指向一个shared_ptr管理的对象。
创建一个weak_ptr时,要用一个shared_ptr来初始化它
auto p = make_shared<int>(42);
weak_ptr<int> wp(p);//wp弱共享p;p的引用计数未改变if(shared_ptr<int> np = wp.lock()){//如果np不为空则条件成立//在if中,np与p共享对象
}
核查指针类:
//对于访问一个不存在元素的尝试,StrBlobPtr抛出一个尝试
class StrBlobPtr{
public:StrBlobPtr(): curr(0){ }StrBlobPtr(StrBlob &a, size_t sz = 0):wptr(a.data), curr(sz){ }std::string& deref() const;StrBlobPtr& incr();//前缀递增
private://若检查成功,check返回一个指向vector的shared_ptrstd::shared_ptr<std::vector<std::string>>check(std::size_t, const std::string&) const;//保存一个weak_ptr,意味着底层vector可能被销毁std::weak_ptr<std::vector<std::string>> wptr;std::size_t curr;//在数组中的当前位置
}//StrBlobPtr的check成员与StrBlob中的同名成员不同,它还要检查指针指向的vector是否还存在
std::shared_ptr<std::vector<std::string>>
StrBlobPtr::check(std::size_t i, const std::string &msg) const
{auto ret = wptr.lock();//vector还存在吗?if(!ret)throw std::runtime_error("unbound StrBlobPtr");if(i>=ret->size())throw std::out_of_range(msg);return ret;//否则,返回指向vector的shared_ptr
}
指针操作:
//deref成员调用check,检查使用vector是否安全以及curr是否在合法范围内
std::string& StrBlobPtr::deref() const
{auto p = check(curr, "dereference past end");return (*p)[curr]; //(*p)是对象所指向的vector
}//incr成员也调用check
//前缀地递增:返回递增后的对象的引用
StrBlobPtr& StrBlobPtr::incr()
{//如果curr已经指向容器的尾后位置,就不能递增它check(curr, "increment past end of StrBlobPtr");++cur;//推进当前位置return *this;
}//对于StrBlob中的友元声明来说,此前置声明是必要的
class StrBlobPtr;
class StrBlob{friend class StrBlobPtr;//返回指向首元素和尾后元素的StrBlobPtrStrBlobPtr begin() { return StrBlobPtr(*this); }StrBlobPtr end(){auto ret = StrBlobPtr(*this, data->size());return ret;}
}
动态数组
new和数组:让new分配一个动态数组,需要在类型名之后跟一对方括号,在其中指明要分配的对象的数目。
//调用get_size确定分配多少个int
int *pia = new int[get_size()];//pia指向第一个inttypedef int arrT[42];//arrT表示42个int的数组类型
int *p = new arrT;//分配一个42个int的数组;p指向第一个int
初始化动态分配对象的数组:默认情况下,new分配的对象,都是默认初始化的。
int *pia = new int[10];//10个未初始化的int
int *pia2 = new int[10];//10个值初始化为0的int
string *psa = new string[10];//10个空string
string *psa2 = new string[10]();//10个空string//10个int分别用列表中对应的初始化器初始化
int *pia3 = new int[10]{0,1,2,3,4,5,6,7,8,9};
//10个string,前4个用给定的初始化器初始化,剩余的进行值初始化
string *psa3 = new string[10]{"a", "an", "the", string(3,'x')};
动态分配一个空数组是合法的:
size_t n = get_size();//get_size返回需要的元素的数目
int* p = new int[n]; //分配数组保存元素
for(int* q = p; q != p+n; ++q)/*处理数组*/;char arr[0];//错误:不能定义长度为0的数组
char *cp = new char[0];//正确:但cp不能解引用
释放动态数组:
delete p;//p必须指向一个动态分配的对象或为空
delete [] pa;//pa必须指向一个动态分配的数组或为空typedef int arrT[42];//arrT是42个int的数组的类型别名
int *p = new arrT;//分配一个42个int的数组;p指向第一个元素
delete []p;//方括号是必须的,因为我们当初分配的是一个数组
智能指针与动态数组:标准库提供了一个可以管理new分配的数组的unique_ptr版本。为了用一个unique_ptr管理动态数组,我们必须在对象类型后面跟一对空方括号。
//up指向一个包含10个未初始化int的数组
unique_ptr<int[]> up(new int[10]);
up.release();//自动用delete[]销毁其指针for(size_t i = 0; i!=10; ++i)up[i] = i;//为每个元素赋予一个新值//为了使用shared_ptr,必须提供一个删除器
shared_ptr<int> sp(new int[10], [](int *p) { delete[] p; });
sp.reset();//使用我们提供的lambda释放数组,它使用delete[]//shared_ptr未定义下标运算符,并且不支持指针的算术运算
for(size_t i=0; i!=10; ++i)*(sp.get() + i) = i;//使用get获取一个内置指针
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GUiCOZIp-1677828130213)(C:\Users\21147\AppData\Roaming\Typora\typora-user-images\1675233306285.png)]
allocator类:定义在头文件memory中,将内存分配和对象构造分离开来。当一个allocator对象分配内存时,它会根据给定的对象类型来确定恰当的内存大小和对齐位置:
allocator<string> alloc;//可以分配string的allocator对象
auto const p = alloc.allocate(n);//分配n个未初始化的string
allocator分配未构造的内存:
auto q = p;//q指向最后构造的元素之后的位置
alloc.construct(q++);//*q为空字符串
alloc.construct(q++, 10, 'c');//*q为cccccccccc
alloc.construct(q++, "hi"); //*q为hicout<<*p<<endl;//正确:使用string的输出运算符
cout<<*q<<endl;//灾难:q指向未构造的内存!
拷贝和填充未初始化内存的算法:
//分配比vi中元素所占用空间大一倍的动态内存
auto p = alloc.allocate(vi.size()*2);
//通过拷贝vi中的元素来构造从p开始的元素
auto q = uninitialized_copy(vi.begin(), vi.end(), p);
//将剩余元素初始化为42
uninitialized_fill_n(q,vi.size(),42);
概念总结
为了更安全地使用动态对象,标准库定义了两个智能指针俩管理动态分配的对象。当一个对象应该被释放时,指向它的智能指针可以确保自动地释放它。
静态内存:保存局部static对象、类static数据成员以及定义在任何函数之外的变量。
栈内存:保存定义在函数内的非static对象。分配在静态或栈内存的对象由编译器自动创建和销毁。
对于栈对象,仅在其定义的程序运行时才存在;static对象在使用之前分配,在程序结束时销毁。
shared_ptr为什么没有release成员?
相关文章:
《C++ Primer》 第十二章 动态内存
《C Primer》 第十二章 动态内存 动态内存与智能指针 shared_ptr允许多个指针指向同一个对象;unique_ptr则“独占”所指向的对象,weak_ptr指向shared_ptr所管理的对象。这三种类型都定义在memory头文件中。 shared_ptr类:默认初始化的智能…...
多个关键字用or、and、包含、不包含动态拼接为正则表达式和SQL查询条件
目录前言校验思路1、存储方式2、实现图一实现图二实现结果最后前言 不知道大家有没有做过这种需求:在某字符串中,根据多个关键字去判断这串字符串是否满足条件。如下图: 亦或是 如果说要根据图二的关键字去数据库中查询符合条件的数据&a…...
初始Linux操作系统
个人简介:云计算网络运维专业人员,了解运维知识,掌握TCP/IP协议,每天分享网络运维知识与技能。座右铭:海不辞水,故能成其大;山不辞石,故能成其高。个人主页:小李会科技的…...
【算法数据结构体系篇class12、13】:二叉树
一、判断二叉树是否是完全二叉树/*** 判断二叉树是否是完全二叉树** //判断层序遍历过程如果节点有右子树 没有左子树 那么就不是完全二叉树* //判断层序遍历过程如果遇到第一个节点是没有左或右子树的,也就是只有一个子节点或者没有,那么再往后层序遍历…...
数字IC手撕代码--联发科(总线访问仲裁)
题目描述当A、B两组的信号请求访问某个模块时,为了保证正确的访问,需要对这些信号进行仲裁。请用Verilog实现一个仲裁器,对两组请求信号进行仲后,要求:协议如图所示,请求方发送req(request&…...
白盒测试复习重点
白盒测试白盒测试之逻辑覆盖法逻辑覆盖用例设计方法1.语句覆盖2.判定覆盖(分支覆盖)3.条件覆盖4.判定条件覆盖5.条件组合覆盖6.路径覆盖白盒测试之基本路径测试法基本路径测试方法的步骤1.根据程序流程图画控制流图2.计算圈复杂度3.导出测试用例4.准备测试用例5.例题白盒测试总…...
学习C++这几个网站足矣
文章目录cppreferencecplusplusquick-bench[C 之父的网站](https://www.stroustrup.com/bs_faq.html)C提案[Cpp Core Guidelines](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines)[C Super-FAQ](https://isocpp.org/faq)[learn c](https://www.learncpp.com/)[A…...
第十四届蓝桥杯模拟赛(第三期)——C语言版
1.找最小数 问题描述: 请找到一个大于 2022 的最小数,这个数转换成十六进制之后,所有的数位(不含前导 0)都为字母(A 到 F)。 请将这个数的十进制形式作为答案提交。 #include <stdio.h> int main(…...
Flutter Button 实例
大家好,我是 17。 在上篇文章 使用 Flutter Button 介绍了如何修改 button 的样式,本文来具体实践一下。 本文列举一些常用的 button 效果,以便在用到的时候方便使用。因为 ElevatedButton 最常用,所以大多以 ElevatedButton 举…...
好玩的docker项目,盒子刷的海思nas,挂载外接硬盘。qb种子
玩法思路(5条消息) 群晖qb下载,tr辅种_屿兮的博客-CSDN博客_群晖辅种qbittorrent简介及设置_哔哩哔哩_bilibiliqb下载器下载Transmission最好用的BT(PT)下载神器/超简单上手教你在NAS轻松部署/告别简陋三步让你升级全中文最新Web界面(BT下载/PT下载/NAS/…...
RabbitMQ的使用
1.初识MQ1.1.同步和异步通讯微服务间通讯有同步和异步两种方式:同步通讯:就像打电话,需要实时响应。异步通讯:就像发邮件,不需要马上回复。两种方式各有优劣,打电话可以立即得到响应,但是你却不…...
Selenium如何隐藏浏览器页面?
Selenium隐藏浏览器页面 背景 在工作,学习中,我们常常会使用selenium来获取网页上的数据,编完完整程序之后,实现真正意义上的自动化获取,此时我们会发现在运行中往往会弹出浏览器页面,在调试过程中&…...
基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离
基于Ant DesignPro Vue实现通过SpringBoot后台加载自定义菜单- 前后端分离 本文想基于Ant DesignPro Vue构建的前端SpringBoot实现的后端接口服务,实现前后端分离开发和独立运行,业务场景是登录认证,认证成功后返回该用户相应权限范围内可见的…...
Acwing---843. n-皇后问题
n-皇后问题1.题目2.基本思想3.代码实现1.题目 n−皇后问题是指将 n 个皇后放在 nn 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。 现在给定整数 n,请你输出所有的满足条件的棋子摆法。 …...
彻底搞清楚内存泄漏的原因,如何避免内存泄漏,如何定位内存泄漏
作为C/C开发人员,内存泄漏是最容易遇到的问题之一,这是由C/C语言的特性引起的。C/C语言与其他语言不同,需要开发者去申请和释放内存,即需要开发者去管理内存,如果内存使用不当,就容易造成段错误(segment fa…...
自动驾驶目标检测项目实战——基于深度学习框架yolov的交通标志检测
自动驾驶目标检测项目实战——基于深度学习框架yolov的交通标志检测 目前目标检测算法有很多,流行的就有faster-rnn和yolov,本文使用了几年前的yolov3框架进行训练,效果还是很好,当然也可以使用更高版本的Yolov进行实战。本代码使…...
flink兼容性验证
flink介绍:https://blog.csdn.net/weixin_43563705/article/details/107604693 一、安装启动 安装flink及其依赖 yum install java-1.8.0-openjdk curl tar mkdir -p /usr/local/flink wget https://mirrors.aliyun.com/apache/flink/flink-1.16.1/flink-1.16.1-bi…...
智慧工厂数字孪生可视化监测系统有效提升厂区安全管控效力
我国制造业正处于产业升级的关键时期,基于数据进行生产策略制定与管理是大势所趋,而数据可视化以更直观的方式成为数据分析传递信息的重要工具。 深圳华锐视点通过三维可视化手段对工厂各类设备进行三维建模,真实复现设备设施外观、结构、运转…...
c++中基本类型详细解释外加基本运算规则
👀👀#c中包括算数类型和空类型。 类型含义wchat_t宽字符bool布尔类型char字符chat16_tunicode字符chat_32unicode字符short短整型int整形long长整型longlong长整型float单精度浮点型double双精度浮点型longdouble扩展精度浮点型 👀…...
扬帆优配“机器人+”方案加码产业发展,这些股有望高增长
“机器人”发明新需求,2022年中国机器人市场规模约为174亿美元。 美国时刻3月1日,特斯拉在得克萨斯州超级工厂举办投资者日活动,展示了人形机器人Optimus的视频,更夸大的是,视频中的机器人好像在制作另一个机器人&…...
推送投票制作微信推送里投票制作教程在线投票活动制作
近些年来,第三方的微信投票制作平台如雨后春笋般络绎不绝。随着手机的互联网的发展及微信开放平台各项基于手机能力的开放,更多人选择微信投票小程序平台,因为它有非常大的优势。1.它比起微信公众号自带的投票系统、传统的H5投票系统有可以图…...
【架构师】跟我一起学架构——微服务分层监控
博客昵称:架构师Cool 最喜欢的座右铭:一以贯之的努力,不得懈怠的人生。 作者简介:一名Coder,软件设计师/鸿蒙高级工程师认证,在备战高级架构师/系统分析师,欢迎关注小弟! 博主小留言…...
Linux:https静态网站搭建案例
目录介绍httpshttps通信过程例介绍https 整个实验是在http实验基础上进行的 因为http协议在传输的时候采用的是明文传输,有安全隐患,所以出现了https(安全套接字层超文本传输协议) HTTPS并不是一个新协议, 而是HTTP…...
前端css整理
如何水平垂直居中一个盒子? 1.已知高度:子盒子设置 display: inline-block; 父盒子设置 line-height 等于高度实现垂直居中;使用 text-align:center实现水平居中 2.父盒子 display:flex; align-items:center;justify-content:center; 3.定位&…...
混凝土搅拌站远程监控解决方案
一、项目背景 随着大规模的基础设施建设,对混凝土搅拌设备的需求量日益增加,对其技术指标的要求也日益提高,其技术性能将直接关系到工程的质量和使用寿命。而混凝土生产的质量是在生产过程中形成的,而非最终强度的检测。混凝土生…...
Spark SQL 学习总结
文章目录(一)Spark SQL(二)SParkSession(三)DataFrame常见算子操作(四)DataFrame的sql操作(五)RDD转换为DataFrame(1)反射方式&#x…...
深度学习 - 37.TF x Keras Deep Cross Network DCN 实现
目录 一.引言 二.模型简介 1.Embedding and stacking layer 2.Cross Network 2.1 模型架构分析 2.2 计算逻辑...
Ubuntu中使用Synaptic进行包管理
Synaptic概况 Synaptic 是一个轻量级的 apt 软件包管理器系统的 GUI 前端,所有你可以在终端中使用 apt-get 命令来做的事,都可以通过 Synaptic 来实现。优势 图形化安装界面,同时可以安装配置相关依赖,避免由于依赖问题导致的各类…...
python之selenium库安装及用法(定位法、获取文本、文本框输入、鼠标点击、滑动滚动条)
一、selenium库安装 pip install selenium二、浏览器驱动安装 谷歌浏览器驱动下载地址:https://chromedriver.storage.googleapis.com/index.html 根据你电脑的谷歌浏览器版本,下载相应的就行。我下载的是110.0.5481.XX中的chromedriver_win32.zip 下载…...
FPGA纯verilog实现图像视频旋转 串口指令控制旋转角度 提供工程源码和技术支持
目录1、前言2、理论基础3、设计思路和框架图像输入和采集图像旋转处理图像缓存图像输出4、vivado工程详解5、上板调试验证6、福利:工程代码的获取1、前言 图像旋转是一种常用的图像处理技术,其基本原理就是指图像以某一点为中心旋转一定的角度ÿ…...
计算机网络实验 做网站的/最近的国内新闻
目录 replace if..else.. ARouter跳转形式 null 判断 过滤 map loading提示 toast调用 打印日志 when 时间控件 Glide 图片加载 防止重点 Dagger 调用 launch Dialog提示 get() 埋点 repeat循环 ActivityManager 延迟加载 runCatch 登录拦截 水纹点击效果 replace tv_nam…...
湖南网站建设策划/网络营销期末考试试题及答案
打包jar上传到服务器 会生成三个文件(就是如图maven-status下面的) 上传到服务器中的jar包一定是最下面那个带有依赖的,才能运行成功。不然会报文件找不到错误 如图就是那个文件找不到...
手工艺品网站建设/产品软文撰写
list的介绍 list的底层是双向带头链表,相对其他容器,list容器不支持随机访问节点,访问list容器的节点都是O(n)级别,但是插入删除都是O(1)级别。 list的迭代器使用 list的跟其他的容器的迭代器实现不同,类似vector容器的迭代器是…...
东阿网站建设费用/个人网站设计
一到晚上这个网慢的呀,我和加载页面一样在原地直打转!不能忍。所以我打算用网线连接提网速。 先分别测试了一下笔记本电脑连WIFI,直连路由器,和直连光猫的网速差距,不测不知道一侧吓一跳,所以我决定从光猫…...
厦门网站建设求职简历/温州seo结算
背景 近几年,前端应用(WebApp)正朝着大规模方向发展,在这个过程中我们会对项目拆解成多个模块/组件来组合使用,以此提高我们代码的复用性,最终提高研发效率。 在编写一个复杂组件的时候,总会依…...
做网站banner是什么意思/百度指数官网入口
开发的项目多种多样,有时候程序员也会遇到瓶颈不知如何往下操作,今天爱站技术频道小编为大家编写了iOS开发之如何给View添加指定位置的边框线详解,希望对大家有所帮助!示例代码封装一:直接封装成了一个方法/// 边框类型…...