C++ Primer笔记(九)

值初始化与默认初始化

初始化指的是在创建变量时赋予一个初始值

默认初始化

  1. 非静态局部变量,如果是内置类型,在函数体内部将不被初始化
  2. 静态局部变量,如果初始化没有赋初值,进行值初始化,内置类型初始化为0
  3. 全局变量 初始化为0
  4. 类类型,按照默认构造函数进行初始化

顺序容器

容器是一些特定类型对象的集合,顺序容器提供了控制元素存储和访问顺序的能力,不依赖于元素的值,而是与元素加入容器时的位置相对应

概述

顺序容器特点
vector可变大小数组,快速随机访问,在尾部之外插入或者删除很慢
deque双端队列,随机访问,头尾插入删除速度很快
list双向链表,只支持双向顺序访问,插入删除速度块
forward_list单向链表(只能递增迭代器),顺序访问,插入删除速度快(C++11)
array固定大小数组,不能添加删除,随机访问(C++11)
string与vector类似,随机访问,尾部插入删除快

vector的初始化方法
在这里插入图片描述

容器库概览

容器操作描述
iterator容器类型的迭代器类型
const_iterator只能读取元素的迭代器类型
size_type无符号整数类型,保存大小
difference_type保存两个迭代器距离
value_type元素类型
reference元素左值类型
const_referenceconst左值类型
Container c执行默认构造函数
Container c(c1)c是c1的拷贝
Container c(b,e)构造c,将b到e指定范围内元素拷贝到c
Container c{a,b,c}列表初始化
c1=c2c1中元素替换为c2中元素
c1={a,b,c}c1中元素替换为列表
c1.swap(c2)c1c2交换元素
c.size()c中元素数目
c.maxsize()c中最大元素数目
c.empty()存储了元素返回false
c.begin() c.end() c.cbegin() c.cend()返回迭代器
== !=所有容器都支持
< <=无序关联容器不支持

对所有容器都适用的操作

  1. 迭代器,一对迭代器(begin end)标识了一个迭代器范围,需要注意的是end迭代器指向的是尾元素之后的位置,这个迭代器范围包含的是从begin开始到end(但不包括end)的范围,是一个左闭合区间。所以当begin==end时, 迭代器范围为空,可以作为判断条件
  2. 反向迭代器的操作与迭代器相反,++操作会得到上一个元素
  3. 每个容器类型都定义了一个默认构造函数。只有顺序容器才能按如下构造:C c(n)或者C c(n,t)分别是包含N个元素和N个初始值为t的元素
  4. 将一个容器创建为另一个的拷贝,可以拷贝容器(要求容器类型和元素类型相同)或者拷贝一个由迭代器指定的元素范围比如:
list<string> authors = {"Milton","Shakespeare", "Austen"};
list<string> list2(authors);//正确
deque<string> authList(authors);//容器类型不匹配
forward_list<string> words(authors.begin(), authors.end())//以迭代器方式初始化

迭代器初始化,新容器中的每个元素都用范围中对应元素的值进行初始化

  1. 与顺序容器大小相关的构造函数:vector<int> vec1(n,5)接受一个容器大小和一个(可选的)元素初始值。vector<int > vec1(ia,ia+4)将vec1初始化为ia的四个值
  2. 特殊:array除了指定元素类型还要指定容器大小array<int, 10>大小是该类型的一部分,所以不支持普通的容器构造函数,默认构造的array非空,元素被默认初始化,如果进行列表初始化且初始值数目小于array的大小,那么剩下的值会被值初始化,如果元素是类类型,那么这个类应当有一个默认构造函数以支持初始化。内置数组类型不支持拷贝和对象赋值,但是array可以

赋值和交换

  1. 赋值操作,必须具有相同的类型,vec1=vec2左边容器中的的全部元素替换为右边容器元素拷贝,且容器大小也被改变为右边容器的大小,并且会使得左边容器的迭代器,引用和指针失效。
  2. 交换操作 不会导致迭代器引用和指针失效,不进行任何拷贝插入删除操作,保证常数时间内完成,并且迭代器等还会指向之前的元素,已经换到另一个容器中;但是swap两个array会真正交换他们的元素,所以所需时间与元素数量成正比,对于array是迭代器指向的元素位置不变,但值发生了改变
  3. 顺序容器定义了一个名为assign的成员,将右边运算对象中所有元素拷贝到左边,不需要相同的类型,但是必须相容,接受迭代器
list<string> names;
vector<const char*> oldstyle;
names=oldstyle;//错误,容器类型不匹配
names.assign(oldstyle.cbegin(),oldstyle.cend());

第二个版本接受一个整型和一个元素,替换容器中原有的元素

大小操作

size()返回容器中元素数目
empty()size为0返回true
max_size返回容纳的最大元素数的值

关系运算符

  1. <= >= == 这类关系运算符必须两边相同容器,保存相同元素,实际上的比较操作是进行元素的逐对比较
  • 容器大小相等,所有元素两两相等,则容器相等
  • 容器大小不同,但小容器每个元素等于较大容器对应元素,则较小容器小于较大容器
  • 如果两个容器都不是另外一个容器的前缀子序列,则比较结果取决于第一个不等元素的比较结果
  1. 容器的相等运算符实际上是利用所含元素的==运算符实现的,同理其他元素运算符,如果元素类型不支持相应运算符,那么容器就不能进行相应的关系运算

顺序容器操作

顺序容器操作会改变大小,故array不支持
forward_list不支持push_back()且由自己版本的insertemplace,vector和string不支持push_front

c.push_back() c.emplace_back()在c的尾部创建一个值为t或者由args构建的元素,返回void
c.push_front() c.emplace_front(args)在c的头部创建一个值为t或者由args构建的的元素,返回void
c.insert(p,t) c.emplace(p,args)在迭代器p指向的元素之前创建一个值为t或者由args创建的元素,返回指向新元素的迭代器
c.insert(p,n,t)在p指向的元素之前插入n个值为t的元素,返回新添加的第一个元素迭代器
c.insert(p,b,e)将迭代器b和e指定的范围内元素插入迭代器p指向的元素之前,b和e不能指向c中元素,返回指向新添加的第一个元素迭代器
c.insert(p,il)il是花括号包围的元素值列表,将这些给定值插入到p指向的元素之前,返回指向新添加的第一个元素迭代器

向一个vector string deque插入元素会导致迭代器,引用和指针失效(插入点/删除点之后全部失效)

添加元素

  1. push_back在容器尾部创建一个新的元素,放入的元素是对象值的拷贝,而不是引用,push_front在头部插入,但vector不支持,deque支持
  2. insert允许在容器任意位置插入元素,将元素插入到迭代器指定的位置之前,也支持插入范围元素,一个版本接受一个迭代器,一个元素数目和一个值,将元素添加到指定位置之前
  3. 使用insert的返回值,可以在容器中特定位置反复插入值,因为insert返回的是添加的第一个元素的迭代器
  4. emplace 这类操作构造而不是拷贝元素,将参数传递给元素类型的构造函数,使用这些参数在容器管理的内存空间中直接构造元素。所以emplace 的参数是与元素类型的构造函数相匹配的。

访问元素

  1. 每个顺序容器都有一个front成员函数,除了forward_list之外都有一个back成员函数,返回首或尾元素的引用,若容器为空则函数行为未定义
  2. .at(n)返回下标为n的元素的引用,下标越界抛出异常
  3. 这几个成员函数返回的是引用,如果容器是const的,则返回const的引用,否则返回普通引用,可以改变元素的值
  4. 提供随机访问的容器也提供下标运算符,但编译器不检查下标是否在合法范围内,可以用异常安全的.at(n)方法替代,这个成员函数抛出异常,而下标运算符,front和back方法对于空容器是行为未定义的。

删除元素

  1. 删除操作改变容器大小,故不适用于array,
pop_back() pop_front()删除c中尾或首元素,若c为空函数行为未定义
erase(p)删除迭代器p所指定的元素,返回一个指向后一个元素的迭代器,若p为尾后迭代器,函数行为未定义
erase(b,e)删除迭代器b和e所指定范围内的元素,返回被删除的最后一个元素之后元素的迭代器,若e为尾后迭代器,则返回尾后迭代器
clear()清除容器所有元素

删除deque除首尾之外任何元素都会使迭代器等失效,指向vector string删除点之后的迭代器等会失效
3. vector和string不支持pop_front,forward_list不支持pop_back,不能对一个空容器执行弹出操作,且这些操作返回void,如果你需要这些元素的值,就应当在弹出操作之前保存它。
4. 如果删除容器内部的元素,erase()方法即可,接受一个迭代器或者一个迭代器范围作为参数,返回最后一个被删除的元素后一个位置元素迭代器
5. forward_list比较特殊,我们提供了insert_after()erase_after()来在接受的迭代器后面插入或者删除元素。另外定义了before_begin()来返回首前迭代器,通过这个迭代器可以操作第一个元素
,所以操作单向列表时,我们要关注当前元素迭代器和前一个元素迭代器,通过当前的判断,通过前一个来操作当前元素。

改变容器大小

  1. resize可以改变容器大小,如果当前大小大于要求大小,容器后部元素被删除,如果当前大小小于要求大小,新元素被添加到元素后部,进行值初始化,类类型提供一个默认构造函数
  2. 如果缩小容器,则指向被删除元素的迭代器、引用、指针都会失效。对vector string deque进行resize可能导致迭代器失效

容器操作导致迭代器失效

  1. 添加或删除元素有可能导致指向容器元素的指针、引用、迭代器失效,如果是添加元素:
    (1)容器是vector或者string 且存储空间重新分配,则迭代器指针引用都会失效,如果未重新分配,则指向插入位置之前的元素迭代器,指针,引用有效,指向插入位置之后的失效
    (2)deque,插入到首尾之外任何位置都会导致迭代器等失效,如果在首尾位置添加元素,仅迭代器失效
    (3)list和forward_list不受影响,指向容器元素的迭代器等不会失效
  2. 删除元素的话:
    (1) 对于list和forward_list,指向容器其他位置的迭代器、引用和指针都有效
    (2)vector和string,被删位置之前的迭代器等都有效
    (3) 对于deque在首尾之外任何位置删除元素都会使迭代器等失效,如果删除尾元素,则尾后迭代器失效,引用和指针不受影响。
  3. 不要保存end返回的迭代器,因为我们添加或者删除vector和string里的元素以及在deque中首尾之外任何位置添加删除元素,尾后迭代器总会失效,如果在一个循环中要向vector string deque中添加或者删除元素,不能保存end返回的迭代器。

vector对象的增长模式

  1. 标准库设计者采取了减少容器空间重新分配次数的策略,当不得不分配新内存空间时,vector和string的实现通常会分配比新的空间需求更大的空间,作为备用
  2. 管理容量的成员函数: shirink_to_fit()capacity()减少为size()一样大小,capacity()不重新分配内存,c可以保存多少元素reserve(n)分配至少能够容n个元素的内存空间
  3. 调用reserve不会减少容器的内存空间,它在需求大小大于当前容量才会改变vector的容量
  4. capacity指的是在不分配新内存空间的前提下它最多可以保存多少元素,而size指的是它已经保存的元素数目

额外的string操作

构造的其他方法

string s(cp,n)s是cp指向的数组中前n个字符的拷贝
string s(s2,pos2)s是string s2从下标pos2开始的拷贝
string s(s2,pos2,len2)s是string s2从下标pos2开始len2个长度的拷贝

如果下标超出了size()的范围,则构造函数的行为是未定义的。
2. substr操作返回一个string的拷贝,接受一个开始位置下标和计数值,计数值参数可选。

改变string的其他方法

  1. 适用于容器的insert emplace erase方法也适用于string ,提供了一个接受下标的版本insert(pos,n,elem)在pos位置插入n个elem元素
  2. string定义了独有的方法 replace()append ()。append在末尾插入字符,replace(a,b,c)将从a开始的b个字符替换为c replace实际上是调用insert和erase的一种简写方式。
string s("C++ Primer"),s2=s;//将s和s2初始化为"C++ Primer"
s.insert(s.size(),"4th ed.");//在尾部插入新字符串
s2.append("4th Ed.");//等价
s.replace(11,3,"5th");//等价于
s.erase(11,3);//
s.insert(11,"5th");

string 搜索操作

  1. string提供了6个不同的搜索函数,返回一个string::size_type来表示匹配字符串的第一个元素下标,如果未找到,返回一个string::npos的成员
    在这里插入图片描述
  2. 在arg中指定的pos为s中开始查找的位置
  3. rfind成员函数是从右到左进行搜索

compare函数

  1. compare函数与c的strcmp函数相似,根据s大于等于还是小于参数指定的字符串,返回正数,0,负数
    参数列表如下图所示:
    在这里插入图片描述

数制转换

  1. 数值数据与标准库string,to_string(i)将一个整数转换为字符表示形式,stod(s)将字符串表示的数字转换为浮点数,string参数中第一个非空白符号必须是+-或数字,可以以0x开头来表示十六进制数字,如果将字符串转换为浮点数,也可以以小数点开头,包含e来表示指数部分。
  2. 如果不能转换为数字,抛出invalid_argument异常,如果数值无法用任何类型表示,抛出out_of_range异常
string和数值之间的转换描述
to_string(val)返回val的string表示,val可以是任何算术类型,
stoi(s,p,b) stol(-) stoul(-) stoll(-) stoull(-)将字符串转化为整数类型,b是转换基数,默认十进制,p保存s中第一个非数值字符下标
stof(s,p) stod(s,p) stold(s,p)返回s的起始子串的数值,表示为浮点数

这些函数是标准库函数,而不是成员函数,可以直接调用

容器适配器

  1. 定义了三个顺序容器适配器:stack queue priority_queue 适配器是一种机制,接受一种容器类型,使其行为看起来像另一种不同类型
  2. 适配器都有两个构造函数,默认构造函数和接受一个容器的构造函数,拷贝该容器来初始化适配器 stack和queue默认是基于deque实现的,但我们可以在创建适配器时,将一个命名的顺序容器作为第二个类型参数来重载默认容器类型 stack<string vector<string>> stk;
  3. 栈适配器,包括pop push emplace top操作 需要注意的是pop无返回值,要访问栈顶元素用top() 每个容器适配器都基于底层容器类型的操作定义了自己的特殊操作,我们只可以使用适配器操作,而不能使用底层容器类型的操作。.push_back()对stack是无效的
  4. 队列适配器操作如下
pop()返回queue的首元素或优先级队列的最高优先级元素
front() back()获取队首或者队尾元素
top()返回最高优先级元素
push()在队尾或者优先级队列合适位置创建元素

数组

  1. 如果要比较字符串的话,c中用strcmp 如果像string一样直接比较,实际比较的是字符串存储的不同地址,未定义 strcmp返回的是第一个不同的字符的ASCII的码的差值(前减后)
  2. String的成员函数c_str()可以用来初始化char字符串 const char *str=string.c_str();
  3. 多维数组在使用范围for语句时,需要对第一个循环变量取引用,否则编译器会将这个变量换为指向变量的指针,就无法进行内层的for循环了
  4. . 二维数组的范围for中,变量类型分别为数组引用和元素类型,而使用指针的for分别为指向数组的指针和指向元素的指针
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值