C++标准库string
与其它常见的初始化方式不同的是,其提供可字符重复(及次数)的初始化方法。其是否使用"="进行初始化与构造函数
的设定有关。(注意初始化时不能使字符串重复初始化而来)
类的初始化方式兼有声明的作用,即同时声明并初始化类实例,这对一些脚本语言(python:基本没有声明的意义,运行时解析)
是无用的。
string具有字符粘贴能力(python 同样有),这为多行输入提供了方便。
string(有size empty方法)与一般脚本str的不同在于,其提供了getline函数,可以输入流(cin或一些文件输入流)作为第一个参数,第二个是输入对象,
这样读入输入流的第一行。这个函数可以用于循环输入(搭配while循环)。
关于string提供的"+"运算符,值得注意的是不能直接对两个字符串常量直接使用,其非string类型。
C++中cctype.h中定义了若干对字符进行判断处理的函数。(include时去掉.h)
由于标准库string提供的方法仅此而已,所以对字符串中的字符进行处理多依赖于cctype库,遍历的操作多依赖于范围for循环。
(进行改变时使用引用:&,这可以对照于python的处理)
还有另外一种处理方式,利用迭代器及algorithm for_each函数但这里需要注意的是,要对其进行修改(toupper)需要将参数设定为引用。
(这也是合理的)这里虽然没有明确说明,但是sting vector等都具有begin end等迭代器。
迭代器与指针类似,(* -> ++ == !=)在对迭代器进行增减循环(一般会利用for_each进行替代)时判断条件多要采用"!=",而非没有规定序
的"<"。
迭代器类型:对于每一个容器,相对应的有迭代器,(Ex : vector::iterator)相应的const迭代器(vector::const_iterator)
与const指针相似,不能对指向的元素进行修改。(相应地对应于cbegin、cend)
这里操作指向的成员多使用->,否则在使用*要加"()"规定优先级(否则出错)
任何想要改变vector大小的操作都会使迭代器失效。
迭代器的基本运算与指针相似,特别地都被重载了 "+="等运算符。
剩余的部分涉及与旧的C的接口,不推荐使用(strlen, strcmp ...)
顺序容器:
顺序容器主要包括(vector deque list forward_list array string)
list不支持随机访问。
考虑对容器的不同处理,list类支持快速地对中间的元素进行修改,但考虑考虑快速随机访问应当对vector类进行。
推荐使用vector 对于在中间插入的情况,推荐对有序时在尾部插入,再利用sort(重载序运算)
无序插入,先对list进行操作,再拷贝到vector中。
在不确定使用哪种容器时,在代码中多使用迭代器,以为修改提供方便。
对容器进行初始化时,一般当只有个数时,相应的类要有默认构造函数,也可以没有,而将除个数外第二个参数指定为用来初始化的
值,即所谓初始化器。
容器有一些通用的相应类型组件,reference是一个,它与iterator相对,用于保持在容器外修改元素的能力。
当然相应的简单方法是auto引用。value_type可以表明元素类型。
这些组件多用于泛型编程中。
容器具有构造拷贝的方法,这种形式可以考虑为构造接口的统一。(如利用向量与矩阵初始化向量)
交换元素的方法为简单的swap,在形式上不用拷贝临时变量进行交换。
常用的对元素操作方法,insert erease(delete) clear emplace(向元素进行写运算 但是是以构造函数参数的形式 而非直接初始化临时对象的方法)
对于顺序容器的迭代器有自增减能力(forward_list除外)
const_iterator 在配合auto方面是有用的,否则准确的类型推断是复杂的。
对顺序容器元素进行初始化当具有形式C c(,,...)时是有三重含义的,
构造函数初始化列表,
若干个具有初始值的元素,
在两个迭代器间的拷贝初始化。(这种初始化方法不要求两个容器元素类型完全相同,只要能进行转换即可)
上面所提到的类型转换与类的其它类型初始化是不同的,其多应用于不能直接运算的操作符,进行类型转换。
其与操作符重载形式相近但不同。其返回值类型在operator后面,没有参数,具有如下形式: operator int(){return real;}
seq暂时不被Code Blocks所支持 暂时不涉及,而且其初始化方法与上面讨论的重复。
对顺序容器的初始化,有一个特例,为array。其在初始化时必须在模板出给出大小:array
且有默认构造函数的类支持初始化空array。
顺序容器中除了array外的容器支持assign方法,将容器替换为相应的形式(是一种完全的替换),其有如下三种形式:
seq.assign(iterator_begin, iterator_end)
seq.assign(num, val)
seq,assign({......})
由于固定大小的限制array不适用assign
swap方法有两种调用形式,但都是对同一种容器使用的。其速度一般比单纯的拷贝快得多。(毕竟相同类型)
swap方法的具体实现对array及其他顺序容器是不同的,对其它顺序容器可以理解为换了名称,而对array,是进行了元素
的拷贝替换,这使得指向容器元素的迭代器在swap前后的表现不同。
对于其它容器,即使进行了swap,指向的元素也是不变的(未交换),对array,指向的元素由于拷贝赋值而改变。
上面的现象对string的操作与array也是一样的。(string不属于标准库容器,已经进行了模板实例化并封装)
顺序容器支持关系运算符比较,其是基于元素封装的关系运算符的,基本符合类字典序。
顺序容器的添加元素操作值得注意的是emplace_back(emplace)
对于插入操作地点的方便记忆方法是,由于迭代器范围导致的插入必须在前面进行。
插入操作与前面的操作相同支持:范围插入,多个同值插入,列表插入。(insert)
考虑到性能问题,对于使用insert()的情况,尽量对list进行。
相应地删除方法:erase(具备单个迭代器删除及范围删除,返回指向删除后元素的迭代器)、clear
在直接利用erase方法删除容器中的元素的情况下,但重复删除时,可能存在迭代器失效的情况,
要使用erase删除元素,一种比较麻烦的方法需要指定两个迭代器,一个用于删除,一个用于指向。
另一种可以利用erase的返回值
由于删除容易出错,故推荐使用标准库algorithm remove方法,remove的具体实现应容器而异,vector remove实现元素移动而非删除,
list remove实现删除(解节点)。
对vector当同时使用两个时(先remove再erase),可以实现元素删除。
对于改变容器大小的操作可能使迭代器失效的问题,要应用(insert erase等的返回迭代器进行处理)
一般的,对于容器元素的操作导致迭代器失效的情况,需要考虑容器的类型,复制、拷贝、解节点这些数据结构底层特性是需要考虑的。
顺序容器提供除了迭代器解引用外的访问首尾元素的方法:front() back() 当容器为空时操作的行为未定义。
对于支持下标运算的容器,类似于dict get方法有相对安全的访问下标方法(.at(num) 如元素不存在,抛出异常)
这里在使用类型推断auto时也要注意改变值要使用引用。
与其它常见的初始化方式不同的是,其提供可字符重复(及次数)的初始化方法。其是否使用"="进行初始化与构造函数
的设定有关。(注意初始化时不能使字符串重复初始化而来)
类的初始化方式兼有声明的作用,即同时声明并初始化类实例,这对一些脚本语言(python:基本没有声明的意义,运行时解析)
是无用的。
string具有字符粘贴能力(python 同样有),这为多行输入提供了方便。
string(有size empty方法)与一般脚本str的不同在于,其提供了getline函数,可以输入流(cin或一些文件输入流)作为第一个参数,第二个是输入对象,
这样读入输入流的第一行。这个函数可以用于循环输入(搭配while循环)。
关于string提供的"+"运算符,值得注意的是不能直接对两个字符串常量直接使用,其非string类型。
C++中cctype.h中定义了若干对字符进行判断处理的函数。(include时去掉.h)
由于标准库string提供的方法仅此而已,所以对字符串中的字符进行处理多依赖于cctype库,遍历的操作多依赖于范围for循环。
(进行改变时使用引用:&,这可以对照于python的处理)
还有另外一种处理方式,利用迭代器及algorithm for_each函数但这里需要注意的是,要对其进行修改(toupper)需要将参数设定为引用。
(这也是合理的)这里虽然没有明确说明,但是sting vector等都具有begin end等迭代器。
迭代器与指针类似,(* -> ++ == !=)在对迭代器进行增减循环(一般会利用for_each进行替代)时判断条件多要采用"!=",而非没有规定序
的"<"。
迭代器类型:对于每一个容器,相对应的有迭代器,(Ex : vector::iterator)相应的const迭代器(vector::const_iterator)
与const指针相似,不能对指向的元素进行修改。(相应地对应于cbegin、cend)
这里操作指向的成员多使用->,否则在使用*要加"()"规定优先级(否则出错)
任何想要改变vector大小的操作都会使迭代器失效。
迭代器的基本运算与指针相似,特别地都被重载了 "+="等运算符。
剩余的部分涉及与旧的C的接口,不推荐使用(strlen, strcmp ...)
顺序容器:
顺序容器主要包括(vector deque list forward_list array string)
list不支持随机访问。
考虑对容器的不同处理,list类支持快速地对中间的元素进行修改,但考虑考虑快速随机访问应当对vector类进行。
推荐使用vector 对于在中间插入的情况,推荐对有序时在尾部插入,再利用sort(重载序运算)
无序插入,先对list进行操作,再拷贝到vector中。
在不确定使用哪种容器时,在代码中多使用迭代器,以为修改提供方便。
对容器进行初始化时,一般当只有个数时,相应的类要有默认构造函数,也可以没有,而将除个数外第二个参数指定为用来初始化的
值,即所谓初始化器。
容器有一些通用的相应类型组件,reference是一个,它与iterator相对,用于保持在容器外修改元素的能力。
当然相应的简单方法是auto引用。value_type可以表明元素类型。
这些组件多用于泛型编程中。
容器具有构造拷贝的方法,这种形式可以考虑为构造接口的统一。(如利用向量与矩阵初始化向量)
交换元素的方法为简单的swap,在形式上不用拷贝临时变量进行交换。
常用的对元素操作方法,insert erease(delete) clear emplace(向元素进行写运算 但是是以构造函数参数的形式 而非直接初始化临时对象的方法)
对于顺序容器的迭代器有自增减能力(forward_list除外)
const_iterator 在配合auto方面是有用的,否则准确的类型推断是复杂的。
对顺序容器元素进行初始化当具有形式C c(,,...)时是有三重含义的,
构造函数初始化列表,
若干个具有初始值的元素,
在两个迭代器间的拷贝初始化。(这种初始化方法不要求两个容器元素类型完全相同,只要能进行转换即可)
上面所提到的类型转换与类的其它类型初始化是不同的,其多应用于不能直接运算的操作符,进行类型转换。
其与操作符重载形式相近但不同。其返回值类型在operator后面,没有参数,具有如下形式: operator int(){return real;}
seq暂时不被Code Blocks所支持 暂时不涉及,而且其初始化方法与上面讨论的重复。
对顺序容器的初始化,有一个特例,为array。其在初始化时必须在模板出给出大小:array
且有默认构造函数的类支持初始化空array。
顺序容器中除了array外的容器支持assign方法,将容器替换为相应的形式(是一种完全的替换),其有如下三种形式:
seq.assign(iterator_begin, iterator_end)
seq.assign(num, val)
seq,assign({......})
由于固定大小的限制array不适用assign
swap方法有两种调用形式,但都是对同一种容器使用的。其速度一般比单纯的拷贝快得多。(毕竟相同类型)
swap方法的具体实现对array及其他顺序容器是不同的,对其它顺序容器可以理解为换了名称,而对array,是进行了元素
的拷贝替换,这使得指向容器元素的迭代器在swap前后的表现不同。
对于其它容器,即使进行了swap,指向的元素也是不变的(未交换),对array,指向的元素由于拷贝赋值而改变。
上面的现象对string的操作与array也是一样的。(string不属于标准库容器,已经进行了模板实例化并封装)
顺序容器支持关系运算符比较,其是基于元素封装的关系运算符的,基本符合类字典序。
顺序容器的添加元素操作值得注意的是emplace_back(emplace)
对于插入操作地点的方便记忆方法是,由于迭代器范围导致的插入必须在前面进行。
插入操作与前面的操作相同支持:范围插入,多个同值插入,列表插入。(insert)
考虑到性能问题,对于使用insert()的情况,尽量对list进行。
相应地删除方法:erase(具备单个迭代器删除及范围删除,返回指向删除后元素的迭代器)、clear
在直接利用erase方法删除容器中的元素的情况下,但重复删除时,可能存在迭代器失效的情况,
要使用erase删除元素,一种比较麻烦的方法需要指定两个迭代器,一个用于删除,一个用于指向。
vectorvi0{1, 1, 5, 6, 5};
vector::iterator vii = vi0.begin();
vector::iterator viii = vi0.begin();
while(viii != vi0.end())
{
if ((*vii) == 5)
{
vi0.erase(vii);
vii = viii;
}
else{
viii++;
vii = viii;
}
}
另一种可以利用erase的返回值
vectorvi{10, 11, 12, 9, 8};
vector::iterator vii = vi.begin();
while(vii != vi.end())
{
if ((*vii) % 2 == 0)
vii = vi.erase(vii);
else
++vii;
}
由于删除容易出错,故推荐使用标准库algorithm remove方法,remove的具体实现应容器而异,vector remove实现元素移动而非删除,
list remove实现删除(解节点)。
对vector当同时使用两个时(先remove再erase),可以实现元素删除。
对于改变容器大小的操作可能使迭代器失效的问题,要应用(insert erase等的返回迭代器进行处理)
一般的,对于容器元素的操作导致迭代器失效的情况,需要考虑容器的类型,复制、拷贝、解节点这些数据结构底层特性是需要考虑的。
顺序容器提供除了迭代器解引用外的访问首尾元素的方法:front() back() 当容器为空时操作的行为未定义。
对于支持下标运算的容器,类似于dict get方法有相对安全的访问下标方法(.at(num) 如元素不存在,抛出异常)
这里在使用类型推断auto时也要注意改变值要使用引用。