028-86922220

建站动态

根据您的个性需求进行定制 先人一步 抢占小程序红利时代

【C++基础】2.标准库-创新互联

8. IO库9. 顺序容器

9.1 顺序容器概述

成都创新互联公司专注于景县网站建设服务及定制,我们拥有丰富的企业做网站经验。 热诚为您提供景县营销型网站建设,景县网站制作、景县网页设计、景县网站官网定制、成都微信小程序服务,打造景县网络公司原创品牌,更为您提供景县网站排名全网营销落地服务。
  • vector:可变大小数组。支持快速随机访问。在尾部之外的位置插入或删除元素很慢
  • deque:双端队列。支持快速随机访问。在头尾位置插入和删除速度很快
  • list:双向链表。只支持双向顺序访问。在list中任何位置进行插入和删除操作速度都很快
  • forward_list:单向链表。只支持单向顺序访问。在链表中任何位置进行插入和删除操作都很快
  • array:固定大小数组。支持快速随机访问。不能添加或删除元素。与内置数组相比,array是一种更安全、更易用的数组类型
  • string:与vector类似,但专门用于保存字符
  • 类型别名:①iterator/const_iterator:此容器类型的迭代器类型;②size_type:无符号整数类型,可保存此容器类型大可能大小;③difference_type:带符号整数类型,可保存两个迭代器之间的距离;④vaule_type:元素类型;⑤reference/const_reference:元素的左值类型
  • 构造函数:①C c;:默认构造函数,构造空容器;②C c1(c2);:拷贝构造函数;③C c(b,e);将迭代器b和e范围内的元素拷贝到c(array不支持);④C c{x,y,z};:列表初始化
  • 赋值与swap:①c1=c2;;②c={x,y,z};;③c1.swap(c2);;(swap通常比拷贝快得多)④swap(c1,c2);(最好统一使用非成员版本的swap,适用于泛型编程)
  • 大小:①c.size():c中元素数目(不支持forward_list);②c.max_size():c中可保存的大元素数目;③c.empty()
  • 添加删除元素(array不支持,不同容器中这些操作的接口都不同):①c.insert(args);②c.emplace(inits);③c.erase(args);④c.clear()
  • 关系运算符:①==/!=:所有容器都支持;②</<=/>/>=:无序关联容器不支持
  • 获取迭代器:c.begin(),c.end()/c.cbegin(),c.cend()
  • 反向容器的额外成员(不支持forward_list):①reverse_iterator/const_reverse_iterator;②c.rbegin(),c.rend()/c.crbegin(),c.crend()

9.2 顺序容器专有操作

  • 初始化(array不可用):①C seq(n);:seq包含n个元素,对这些元素进行值初始化,此构造函数是explicit的(string不可用);②C seq(n,t);:seq包含n个初始化为t的元素
  • 赋值(array不适用):①seq.assign(b,e);:将seq中元素替换为迭代器b和e范围内的元素,b和e不能指向seq本身;②seq.assign(il);:将seq中的元素替换为初始化列表il中的元素;③seq.assign(n,t);:将seq中的元素替换为n个值为t的元素
  • 添加元素(array不可用):①c.push_back(t)/c.emplace_back(args):在c的尾部创建一个值为t或由args创建的元素,返回void(forward_list不可用);②c.push_front(t)/c.emplace_front(args):在c的头部创建一个元素,返回void(vector和string不可用);③c.insert(p,t)/c.emplace(p,args):在迭代器p指向的元素之前创建一个元素,返回指向新添加的元素的迭代器;④c.insert(p,n,t)/c.insert(p,b,e)/c.insert(p,il)
  • 访问元素(返回的均为引用):①c.back()(forward_list不可用);②c.front();③c[n]/c.at(n)(只能用于string、vector、deque、array)
  • 删除元素:①c.pop_back():删除c中尾元素(forward_list不可用);②c.pop_front():删除c中首元素(vector和string不可用);③c.erase(p):删除迭代器p所指向元素,返回被删元素之后元素的迭代器;④c.erase(b,e):删除迭代器b和e范围内的元素,返回最后一个被删元素之后元素的迭代器;⑤c.clear():删除c中所有元素,返回void
  • 改变容器大小:①c.resize(n):调整c的大小为n个元素,添加的新元素进行值初始化,若n小于原长度,则多出的元素被丢弃;②c.resize(n,t):添加的新元素初始化为值t

9.3 额外的string操作

9.4 容器适配器

10. 泛型算法

10.1 泛型算法概述

sort(v.begin(),v.end());	//排序
auto end_unique = unique(v.begin(),v.end());	//unique函数实现无重复排列,返回指向不重复区域的尾后迭代器
v.erase(end_unique,v.end());	//删除重复单词

10.2 定制操作

[capture list] (parameter list) ->return type {function body}

其中,捕获列表是一个lambda所在函数中定义的局部变量的列表,通常为空,参数列表、返回类型、函数体与普通函数一样,但是lambda必须使用尾置返回来指定返回类型。lambda可以忽略参数列表和返回类型,但必须包含捕获列表和函数体:auto f = []{return 10;};,忽略参数列表即参数列表为空,忽略返回类型则从函数体代码中推断返回类型,若函数体中包含单一return之外的内容且未指定返回类型,则返回void

//将words按长度稳定排序
stable_sort(words.begin(),words.end(),[](const string &a,const string &b){return a.size()return a.size()>=sz;});
//从wc迭代器开始打印单词,每个单词后接一个空格
for_each(wc,words.end(),[](const string &s){cout<

10.3 再探迭代器

istream_iteratorin(is);	//in从输入流is读取类型为T的值
istream_iteratorend;	//读取类型为T的尾后迭代器
ostream_iteratorout(os);	//out将类型为T的值写到输出流os中
ostream_iteratorout(os,d);	//out将类型为T的值写到输出流os中,且每个值后都输出一个d,d为C风格的字符串

10.4 泛型算法结构

  1. 输入迭代器:只读,不写,单遍扫描,只能递增;
  2. 输出迭代器:只写,不读,单遍扫描,只能递增;
  3. 前向迭代器:可读写,多遍扫描,只能递增;
  4. 双向迭代器:可读写,多遍扫描,可递增递减;
  5. 随机访问迭代器:可读写,多遍扫描,支持全部迭代器运算
  1. 输入迭代器:① 用于比较两个迭代器的相等==和不相等运算符!=;② 迭代器的前置和后置递增运算++;③ 用于读取元素的解引用运算符*(只会出现在赋值运算符的右侧);④ 用于解引用迭代器并提取成员的箭头运算符->
  2. 输出迭代器:与1类似,解引用运算符只能出现在赋值运算符的左侧
  3. 前向迭代器:1和2会破环迭代器原本结构,只能单遍扫描,前向迭代器可以保存当前状态,多次读写同一个元素
  4. 双向迭代器:还支持前置和后置的递减运算符--
  5. 随机访问迭代器:还支持 ① 用于比较两个迭代器相对位置的关系运算符<,<=,>,>=;② 迭代器和一个整数值的加减运算+,+=,-,-=;③ 用于两个迭代器的减法运算-;④ 下标运算符iter[n],*iter[n](两者等价)
alg(beg,end,other args);
alg(beg,end,dest,other args);
alg(beg,end,beg2,other args);
alg(beg,end,beg2,end2,other args);
11. 关联容器

11.1 关联容器概述

  • 关联容器中的元素是按关键字来保存和访问的,两个主要的关联容器类型是mapset,标准库提供8个关联容器,其不同体现在3个维度上:① set或map;② 是否允许重复的关键字,允许重复关键字的容器以multi开头;③ 是否按顺序保存元素,不按关键字顺序存储的容器以unordered_开头
  • map和multimap定义在头文件中,set和multiset定义在头文件中,unordered_multimapunordered_multiset定义在头文件
  • 关联容器对其关键字类型有限制,有序容器的关键字类型必须定义元素比较的方法,默认情况下标准库使用<运算符来比较两个关键字
  • 头文件中,定义了名为pair的标准库类型,一个pair保存两个数据成员,当创建一个pair时,必须提供两个类型名,pair的默认构造函数对数据成员进行值初始化,map中的元素是pair,标准库中的pair操作包括:①pairp;②pairp(v1,v2);③make_pair(v1,v2);④p.firstp.second

11.2 关联容器操作

  • 关联容器还定义了3仲类型:①key_value:关键字类型;②mapped_type:map的值类型;③value_type:对于set为关键字类型,对于map为pair
  • 当解引用一个关联容i去迭代器时,会得到一个类型为容器的value_type的值的引用。对map而言,会返回一个pair类型,其first成员保存const关键字,不能修改,second成员保存值,可以修改;对set而言,会返回const关键字,不能修改。当使用一个迭代器遍历一个有序关联容器时,迭代器按关键字升序遍历元素
  • 遍历关联容器:
auto m_it = m.cbegin();
while(m_it != m.cend()){cout<< m_it->first<< ":"<< m_it->second<< endl;
	++m_it;
}
  • 关联容器的insert()成员向容器中添加一个元素或一个元素范围,由于map和set包含不重复的关键字,因此插入一个已存在的元素对容器没有任何影响:①c.insert(v)/c.emplace(args):v为value_type类型的对象,args用来构造一个元素;②c.insert(b,e)/c.insert(il):b和e是迭代器,il是花括号列表;③c.insert(p,v)/c.emplace(p,args):将迭代器p作为一个提示,指出从哪里开始搜索新元素应该存储的位置。对于不包括重复关键字的容器,添加单一元素的insert和emplace返回一个pair,pair的first成员是一个迭代器,指向具有给定关键字的元素,second成员是一个bool值,指出元素是插入成功还是已存在于容器中
  • 从关联容器中删除元素:①c.erase(k):从c中删除每个关键字为k的元素,返回删除元素的数量;②c.erase(p):从c中删除迭代器p指定的元素,返回一个p之后的迭代器;③c.erase(b.e):删除迭代器b和e范围中的元素,返回e
  • map和unordered_map容器提供了下标运算符和一个对应的at函数,set、multimap、unordered_multimap不支持下标:①c[k]:返回关键字为k的元素,若k不在c中,添加一个关键字为k的元素,对其进行值初始化;②c.at(k):访问关键字为k的元素,若k不在c中,抛出一个out_of_range异常
  • 在一个关联容器中查找元素:①c.find(k):返回一个迭代器,指向第一个关键字为k的元素,若k不在容器中,则返回尾后迭代器;②c.count(k):返回关键字等于k的元素的数量;③c.lower_bound(k):返回一个迭代器,指向第一个关键字不小于k的元素(不适用于无序容器);④c.upper_bound(k):返回一个迭代器,指向第一个关键字大于k的元素(可与上一个函数一起给定在multimap或multiset中某个关键字对应的迭代器范围);⑤c.equal_range(k):返回一个迭代器pair,表示关键字等于k的元素的范围,若k不存在,pair两个成员均等于c.end()
  • 无序容器:新标准定义了4个无序关联容器,这些容器不使用比较运算符来组织元素,而是使用一个哈希函数和关键字类型的==运算符。无序容器在存储上组织为一组桶,每个桶保存零个或多个元素,使用一个哈希函数将元素映射到桶。如果容器允许重复关键字,所有具有相同关键字的元素都会在同一个桶中,因此无序容器的性能依赖于哈希函数的质量和桶的数量和大小。理想情况下,哈希函数会将每个特定的值映射到唯一的桶,但是将不同关键字的元素映射到相同的桶也是允许的,当一个桶保存多个元素时,需要顺序搜索这些元素来查找想要的那个
12. 动态内存

12.1 对象与内存分配关系

  • 程序中所使用的对象都有严格定义的生存期,全局对象在程序启动时分配,在 程序结束时销毁;局部自动对象在进入其定义所在程序块时被创建,在离开块时销毁;局部static对象在第一次使用前分配,在程序结束时销毁。除了自动和static对象外,C++还支持动态分配对象,动态分配的对象的生存期与它们在哪里创建是无关的,只有当显式地被释放时,这些对象才会销毁
  • 动态对象地正确释放是及其容器出错地地方,为了更安全地使用动态对象,标准库定义了两个智能指针类型来管理动态分配的对象,当一个对象应该被释放时,指向它的智能指针可以确保自动地释放它
  • 静态内存用来保存局部static对象、类static数据成员、定义在任何函数之外的变量,栈内存用来保存定义在函数内的非static对象。分配在静态或栈内存中的对象由编译器自动创建和销毁,栈对象仅在其定义的程序块运行时才存在,static对象在使用前分配,程序结束时销毁。除了静态内存和栈内存,每个程序还有一个内存池,这部分内存被称为自由空间或堆,程序用堆来存储动态分配的对象

12.2 动态内存与智能指针

  • 在C++中,动态内存的管理是通过一对运算符来完成的:①new:在动态内存中为对象分配空间并返回一个指向该对象的指针;②delete:接受一个动态对象的指针,销毁该对象并释放与之关联的内存
  • 为了更容易也更安全地使用动态内存,新的标准库提供了两种智能指针类型来管理动态对象,智能指针负责自动释放所指向地对象,这两种智能指针地区别在于管理底层指针的方式:①shared_ptr:允许多个指针指向同一个对象;②unique_ptr:独占所指向的对象。标准库还定义了一个名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象,这三种类型都定义在头文件中
  • 智能指针也是模板,创建一个智能指针时,必须提供指针可以指向的类型,默认初始化的智能指针中保存着一个空指针:shared_ptrp1;,智能指针的使用方法与普通指针类似,解引用一个智能指针返回它指向的对象,如果在一个条件判断中使用智能指针,就是检测它是否为空
  • shared_ptr和unique_ptr都支持的操作有:①shared_ptrsp/unique_ptrup:空智能指针;②p.get():返回p中保存的指针,要小心使用,若智能指针释放了其对象,返回的指针所指向的对象也就消失了;③swap(p,q)/p.swap(q):交换p和q中的指针
  • shared_ptr独有的操作:①make_shared(args):返回一个指向类型T对象的智能指针,使用args初始化此对象;②sharedp(q):p是q的拷贝,此操作会递增q中的计数器,q中的指针必须能转换为T*;③p = q:p和q所保存的指针必须能相互转换,此操作会递减p的引用计数,递增q的引用计数,若p的引用计数变为0,则将其管理的原内存释放;④p.use_count():返回与p共享对象的智能指针对象,该操作很慢,主要用于调试;⑤p.unique():若p.use_count()为1,返回true,否则返回false
  • 可以认为每个shared_ptr都有一个关联的计数器,称之为引用计数,当拷贝一个shared_ptr时,计数器会递增,当为shared_ptr赋予一个新值或shared_ptr被销毁(如局部shared_ptr离开其作用域)时,计数器就会递减。用哪种数据结构来记录有多少指针共享对象,完全由标准库的具体实现来决定
  • shared_ptr的析构函数会递减它所指向的对象的引用计数,如果引用计数变为0,shared_ptr的析构函数就会销毁对象,并释放它所占用的内存
  • 默认情况下,动态分配的对象是默认初始化的:int *p = new int;,*p的值未定义,在类型名后跟一对括号即可对动态分配的对象进行值初始化:int *p = new int();:*p的值为0
  • 如果提供了一个括号包围的初始化器,就可以使用auto从该初始化器来推断想要分配的对象的类型:auto p = new auto(obj);,p指向一个与obj类型相同的对象,该对象用obj进行初始化,当且仅当括号中有单一初始化器时才可使用auto
  • 类似于其他任何const对象,一个动态分配的const对象必须进行初始化,对于一个定义了默认构造函数的类类型,其const动态对象可以隐式初始化,而其他类型的对象必须显式初始化:const int *p = new const int(10);,new返回的指针是一个指向const的指针
  • 若一个程序用光了它所有可用的内存,new表达式就会失败,默认情况下,如果new不能分配所要求的内存空间,就会抛出一个类型为bad_alloc的异常,可通过int* p = new (nothrow) int;的方式阻止抛出异常,这种形式的new称为定位new

12.3 智能指针的使用

  • 若不初始化一个智能指针,它就会被初始化为一个空指针,还可以使用new返回的指针来初始化智能指针:shared_ptrp(new int(10));,接受指针参数的智能指针构造函数是explicit的,因此不能将一个内置指针隐式转换为一个智能指针,必须使用直接初始化的形式
  • 定义和改变shared_ptr的方法:①shared_ptrp(q):p管理内置指针q所指向的对象,q必须指向new分配的内存,且能偶转换为T*类型;②shared_ptrp(u):p从unique_ptr u那里接管了对象的所有权,将u置为空;③shared_ptrp(q,d):p使用可调用对象d来代替delete;④shared_ptrp(p2,d):p是shared_ptr p2的拷贝;⑤p.reset()/p.reset(q)/p.reset(q,d):若p是唯一指向其对象的shared_ptr,reset会释放此对象,并将p置为空;若传递了参数内置指针q,会令p指向q;若还传递了参数d,会调用d来代替delete
  • 注意事项:① 不要混用普通指针和智能指针:当将一个shared_ptr绑定到一个普通指针时,就将内存的管理责任交给了这个shared_ptr,此时就不该再使用内置指针来访为shared_ptr所指向的内存了,因为无法知道对象何时会被销毁;② 不要使用get()初始化另一个智能指针或为智能指针赋值:这样做会导致内存被二次delete,get()只有在确定代码不会delete指针的情况下使用
  • 有些没有定义析构函数的类,需要用户显式地释放所使用地资源,如果忘记释放资源或在释放之前放生了异常,程序会发生资源泄露。可以将释放资源的函数作为删除器与原对象一起传入智能指针:shared_ptrp(&con,disconnection);,此时资源会自动释放
  • 与shared_ptr不同,某个时刻只能有一个unique_ptr指向一个给定对象,当unique_ptr被销毁时,它所指向的对象也被销毁。unique_ptr没有类似make_shared的标准库函数,必须将其绑定在一个new返回的指针上,unique_ptr不支持普通的拷贝或赋值
  • unique_ptr操作:①unique_ptru(d):创建一个空unique_ptr,指向类型为T的对象,用类型为D的对象d代替delete;②u.release():放弃对指针的控制权,将u置为空并返回指针;③u.reset()/u.reset(q)/u.reset(nullptr):释放u指向的对象,如果提供了内置指针q,令u指向这个对象,否则将u置为空
  • 可以通过调用release或reset将指针的所有权从一个非const的unique_ptr转移给另一个unique_ptr:unique_ptrp2(p1.release())/p2.reset(p1.release())。直接使用release并不会释放内存,而且会丢失指针。可以拷贝或赋值一个将要被销毁的unique_ptr,如从函数返回一个unique_ptr。重载一个unique_ptr的删除器必须在尖括号中提供删除器类型:unique_ptrp(&con,disconnection);
  • weak_ptr是一种不控制所指向对象生存期的智能指针,它指向由一个shared_ptr管理的对象,绑定weak_ptr不会改变shared_ptr的引用计数,一旦最后一个指向对象的shared_ptr被销毁,对象就会被释放,无论还有没有weak_ptr指向它
  • weak_ptr操作:①weak_ptrw(sp)/w = sp:将w指向shared_ptr指针sp指向的对象;②w.reset():将w置为空;③w.use_count():与w共享的shared_ptr的数量;④w.expired():若w.use_count()为0,返回true,否则返回false;⑤w.lock():若w.expired()为true,返回一个空shared_ptr,否则返回一个指向w的对象的shared_ptr

12.4 动态数组

  • new和delete运算符一次分配和释放一个对象,C++和标准库还提供了两种一次分配一个对象数组的方法:① C++定义了另一种new表达式语法,可以分配并初始化一个对象数组;② 标准库中包含了一个名为allocator的类,可以将分配和初始化分离。大多数应用都没有直接访问动态数组的需求,使用标准库容器会更加简单和快速
  • 使用new分配动态数组时,要指明分配的对象的数目:int *p = new int[10];,此时会得到一个元素类型的指针(动态数组并不是数组类型),由于分配的内存并不是一个数组类型,因此不能对动态数组调用begin或end。new分配的对象,无论是单个分配还是数组中的都是默认初始化的,加上空括号后变为值初始化:int *p = new int[10]();,释放动态数组:delete [] p;
  • 标准库提供了一个可以管理new分配的数组的unique_ptr版本:unique_ptrp(new int[]10);,可以使用下标运算符来访问数组中的元素。与unique_ptr不同,shared_ptr不直接支持管理动态数组,如果要使用shared_ptr管理,必须提供自定义的删除器shared_ptrp(new int[10],[](int *p){delete[] p});,并且不能使用下标运算符,只能用gert()获取内置指针后再访问数组元素
  • new将内存分配和对象构造结合在了一起,delete将对象析构和内存释放结合在了一起,这样在分配少量对象时方便使用,但是当要分配大量内存时,希望将内存分配和对象构造分离。标准库allocator定义在头文件中,提供了一种类型感知的内存分配方法,分配的内存是未构造的
  • allocator类算法:①allocatora:定义一个可以为类型T分配内存的allocator对象;②a.allocator(n):分配一段可以保存n个类型为T的对象的未构造的内存;③a.deallocator(p,n):释放从T*指针p开始的n个T类型对象的内存,p必须分配过n个T类型对象,且已被创建的对象必须调用过destroy;④a.construct(p,args):在p指向的未构造内存中通过args构造一个对象;⑤a.destory(p):对p指向的对象执行析构函数;⑥uninitialized_copy(b,e,b2)/uninitialized_copy_n(b,n,b2):将迭代器b到e中的元素拷贝到迭代器b2指向的未构造内存中,b2的内存必须足够大;⑦uninitialized_fill(b,e,t)/uninitialized_fill_n(b,n,t):在迭代器b到e的未构造内存中放入值为t的拷贝

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


分享名称:【C++基础】2.标准库-创新互联
文章路径:http://www.tsicrk.com/article/dsdpdc.html
  • 网站建设专属方案

  • 网站定制化设计

  • 7X24小时服务

  • N对管家服务

让你的专属顾问为你服务

0.8078s