string类是由头文件string支持的。
string类位于命名空间std中。
ctor标识是传统C++中构造函数的缩写。NBTS是以空字符结束的传统C字符串的缩写。
string stuff;
cin >> stuff; // 第一种方式
getline(cin,stuff); // 第二种方式
//输出方式
cout << stuff;
find()
查找字符串或字符首次出现的位置;rfind()
查找字符串或字符最后一次出现的位置;find_first_of()
查找参数中任何一个字符首次出现的位置;find_last_of()
查找参数中任何一个字符最后一次出现的位置;find_first_not_of()
查找第一个不包含在参数中的字符出现的位置。// 寻找hark中任意一个字母h、a、r、k第一次在stuff中出现的位置
int where = stuff.find_first_of("hark");
智能指针是行为类似于指针的类对象,并且该对象还具有其他功能。
要创建智能指针对象,必须包含头文件memory。
智能指针位于命名空间std中。
三个智能指针模板(auto_ptr、unique_ptr、shared_ptr)都定义了类似指针的对象,可以将new获得的地址赋给这些对象;在智能指针过期时,这些内存将自动被释放(不需要手动delete)。
初始化智能指针
// 初始化指向double类型的智能指针
auto_ptr<double> pd(new double);
auto_ptr<double> pd = new double;
unique_ptr<double> p(new double);
shared_ptr<double> pi(new double);
注意
所有智能指针类都有一个explicit构造函数,因此不能隐式将普通指针转换为智能指针,需要进行显式转换。
shared_ptr<double> pd;
double *p_reg = new double;
pd = shared_ptr<double>(p_reg);
智能指针对象可以进行类似于常规指针的操作:解除引用操作(*pd)、用它来访问结构成员(pd->puffIndex)、将它赋值给指向相同类型的常规指针。
注意
智能指针指向的内存必须由new分配,因为智能指针最后将调用delete。
auto_ptr和unique_ptr
建立所有权概念,当使用赋值运算符时,所有权从一个智能指针转移到另一个智能指针,释放所有权的智能指针不再指向原来的内存,成为一个空指针。shared_ptr
跟踪引用特定对象的智能指针数,称为引用计数。当进行赋值操作时,计数将加1,指针过期时,计数将减1.仅当最后一个指针过期时,才调用delete。shared_ptr和auto_ptr
只能赋值new分配内存的地址;unique_ptr
中既可以赋值使用new分配内存的地址,也可以赋值使用new[]分配内存的地址。 如果程序需要使用多个指向同一个对象的指针,则使用shared_ptr
(如果编译器没有提供,可以使用Boost库提供的shared_ptr)。
如果程序不需要多个指向同一个对象的指针,则可以使用unique_ptr。
STL提供了一组表示容器、迭代器、函数对象和算法的模板。
容器
是一个与数组类似的单元,可以存储若干个值。STL的容器是同质的,即存储的值的类型相同;
算法
是完成特定任务(如对数组进行排序)的处方;
迭代器
能够用来遍历容器的对象,与遍历数组的指针类似,是广义指针(可对其执行类似指针的操作,如解除引用和递增等),通过将指针广义化为迭代器,能够为各种不同的容器类(包括哪些简单指针无法处理的类)提供统一的接口;
函数对象
是类似于函数的对象,可以是类对象或函数指针。
此处的vector(矢量)对应数组;
可以进行vector对象的创建,将一个vector对象赋给另一个vector对象,使用[]
来访问vector元素;
vector模板使用动态内存分配,可以用初始化参数来指出需要多少矢量;
使用
表示法来指出要使用的类型。
// 包含vector的头文件
#include
// vector在std中
using namespace std;
// 初始化元素为int类型的vector
vector<int> ratings(5);
// 通过[]来访问vector元素
ratings[0] = 9;
size()
返回容器中元素数目;
swap()
交换两个容器的内容;
begin()
返回一个指向容器中第一个元素的迭代器;
end()
返回一个表示超过容器尾的迭代器(指向容器最后一个元素后面的那个元素位置);
push_back()
将元素添加到矢量(vector)末尾;
erase()
删除矢量中给定区间的元素;
insert()
插入指定区间的元素到指定位置;
// 初始化一个double容器的迭代器
vector<double>::iterator pd;
// 初始化一个double容器
vector<double> scores;
// 将迭代器指向容器pd的首元素
pd = scores.begin();
// 通过迭代器给元素赋值(类似指针)
*pd = 22.3;
// 将迭代器指向下一个元素
++pd;
此处可以使用自动类型推断来定义合适类型的迭代器
vector<double>::iterator pd = scores.begin(); // 直接定义pd
auto pd = scores.begin(); // 使用auto定义pd
double temp;
cin >> temp;
scores.push_back(temp); // 将temp添加到double矢量scores队尾
erase()
第一个参数为指向区间起始处的迭代器,第二个参数为指向区间终值处后一个位置的迭代器,即是一个左闭右开区间。// 删除sorces容器当中begin()和begin()+1指向的元素
scores.erase(scores.begin(),scores.begin()+2);
insert()
接受三个迭代器参数,第一个参数指定了新元素插入的位置(新元素将插入到第一个参数对应的迭代器的前面),第二个和第三个迭代器参数定义了被插入区间(左闭右开),该区间通常是另一个容器对象的一部分。vector<int> old_v;
vector<int> new_v;
...
// 将new_v中除第一个元素外的所有元素插入到old_v的第一个元素前面
old_v.insert(old_v.begin(),new_v.begin()+1,new_v.end());
STL从更广泛的角度定义了非成员函数,即定义了使用于所有容器的函数。
比较有代表性的三个函数:
for_each()
接受三个参数,前两个是定义容器中区间的迭代器(规定了容器对象,即迭代器指向的对象),最后一个是指向函数的指针(一个函数对象)。该非成员函数将被指向的函数应用于容器区间中的各个元素。被指向的函数不能修改容器元素的值。(该函数可以用于任何容器)
random_shuffle()
接收两个指定区间的迭代器参数,并随机排列该区间内的所有元素。(该函数要求容器可以随机访问)
sort()
有两个版本(该函数要求容器可以随机访问)
第一个版本接收两个定义区间的迭代器参数,并使用为存储在容器中的类型元素定义的<
运算符,对区间中的元素进行操作,按照定义的<
以升序进行排序。(如vector中的元素是stuff类,则在stuff类中提供成员或非成员函数operator<()
即可时用sort()
对此类容器进行排序)
第二个版本接收三个参数,前两个参数是指定区间的迭代器,最后一个参数是指向要使用的函数指针(函数对象)。该函数对象的返回值转换成bool型,false表示顺序不正确。
基于范围的for循环是为用于STL而设计的。
// 假设已经实例化了容器books和不修改元素的函数ShowReview、修改元素的函数InflateReview
// 使用for_each对其中元素进行操作
for_each(books.begin(),books.end(),ShowReview)
// 使用基于范围的for循环进行相同操作
for(auto x : books) ShowReview(x);
// 将类型设置为引用可以直接修改容器中的元素
for(auto & x :books) InflateReview(x);
泛型编程旨在编写独立于数据类型的代码。
迭代器是广义指针,而指针满足所有迭代器要求。STL算法可以使用指针来对基于指针的非STL容器进行操作。
#include
#include
using namespace std;
...
ostream_iterator<int,char> out_iter(cout," ");
*cout_iter++ = 15; // 类似 cout << 15 << " "; 并为下一次输出做好准备
copy(dice.begin(),dice.end(),out_iter); // 容器dice该区间中的内容
--------------------------------------------------------------------------
// 也可以使用匿名迭代器如下
copy(dice.begin(),dice.end(),ostream_iterator<int,char>(cout," "));
insert_iterator<vector<int>> insert_iter(dice,dice.begin());
创建用于指示将数据插入到vector
类型容器dice
首元素之前的insert_iterator
迭代器。其中第一个参数表示容器变量,第二个参数表示要插入的位置。
list<int> one; // 实例化一个list
merge()
合并两个链表并排序,保存到调用链表当中,清空另一个链表;
remove()
从链表当中删除所有val元素(如删除整数链表当中所有的2);
sort()
排序;
splice()
将链表x插入到调用链表的pos前面,并清空x;
unique()
将连续的相同元素合并成一个(如将连续的多个元素2合并成一个元素2)。
priority_queue<int> pq1; // 默认比较方式
priority_queue<int> pq2(greater<int>); // 通过参数greater修改比较方式,如对于string元素使用greater
copy()
、for_each()
)。关联容器将值与键关联在一起,并使用键来查找值。
对于容器X
,表达式X::value_type
指出了容器中值的类型,对于关联容器来说,表达式X::key_type
指出了键的类型。
STL提供了四种关联容器set、multiset
(在头文件set中定义),map、multimap
(在头文件map中定义)。
set
值类型与键相同,键是唯一的,集合不会有多个相同的键(值)。对于set来说值就是键;
multiset
类似于set,只是可能有多个值的键相同;
map
值与键的类型不同,键是唯一的,每个键只对应一个值;
multimap
与map相似,但一个键可以与多个值相关联。
set(集合)
(1)实例化一个set
set<string> A;
set<string,less<string>> A; // 若为int集合则应使用less
第二个参数是可选的,用于指示用来对键进行排序的比较函数或对象。
(2)初始化并显示set
const int N = 6;
string s1[N] = {"buffoon","thinkers","for","heavy","can","for"};
set<string> A(s1,s1+N); // 使用指针作为迭代器参数,将s1的所有元素赋值给关联容器A
// 关联容器会自动将元素排序,并合并相同的元素
// 输出A
ostream_iteratro<string,char> out(cout," ");
copy(A.begin(),A.end(),out);
-------------------------------------------------------------------------------
结果:buffoon can for heavy thinkers
(3)基本使用方法
set_union()
求并集;
set_intersection()
求交集;
set_difference()
两个集合相减,消除第一个集合中包含在第二个集合里的元素;
lower_bound()
将键作为参数返回一个迭代器,该迭代器指向集合中第一个不小于键参数的成员;
upper_bound()
将键作为参数返回一个迭代器,该迭代器指向集合中第一个大于键参数的成员;
insert()
插入元素,可以插入单个元素,也可以插入一个集合区间中的所有元素。
set_union()、set_intersection()、set_difference()
均接受5个迭代器参数,其中前两个迭代器定义了第一个集合的区间(记为集合A),接下来的两个迭代器定义了第二个集合区间(记为集合B),最后一个迭代器是输出迭代器
函数 | 功能 |
---|---|
set_union() | A ∪ B A\cup B A∪B |
set_intersection() | A ∩ B A\cap B A∩B |
set_difference() | A − A ∩ B A-A\cap B A−A∩B |
其中输出迭代器可以通过cout
显示也可以输出到其他的集合当中
// 显示合并集合
set_union(A.begin(),A.end(),B.begin(),B.end(),ostream_iterator<string,char> out(cout," "));
// 将合并的集合保存到集合C中,插入到C的首个元素前面
set_union(A.begin(),A.end(),B.begin(),B.end(),ostream_iterator<set<string>>(C,C.begin()));
使用insert()
插入元素并使用lower_bound()、upper_bound()
进行输出
set<string> C;
string s1[6] = {"any","buffoon","can","deliver","elegant","food","for","grungy","heavy","metal","thinkers"};
C.insert(s1,s1+6);
copy(C.lower_bound("ghost"),C.upper_bound("spook"),ostream_iterator<string,char> out(cout," "));
-----------------------------------------------------------------------------------------------------------
结果: grungy heavy metal
multimap
(1)创建multimap对象
创建一个键为int类型,值为string类型的multimap对象;
第三个参数为可选参数,指出用于对键进行排序的比较函数或对象,multimap按键排序。
multimap<int,string> codes;
(2)创建值并插入到multimap对象
// 创建codes对象存储类型的值item pair
pair<const int,string> item(213,"Los Angeles");
// 将pair插入到codes
codes.insert(item);
//直接插入匿名对象
codes.insert(pair<const int,string> (213,"Los Angeles"));
// 可以使用first、second访问pair对象的两个部分
cout << item.first << ' ' << item.second << endl;
(3)获取multimap对象的信息
count()
接收键作为参数,返回具有该键的元素数目
lower_bound()
同set
upper_bound()
同set
equal_range()
接收键作为参数,返回两个迭代器,他们表示的区间与该键匹配(返回区间中的元素的键均为该参数值)。为返回两个参数,将两个迭代器放在一个pair对象中。
打印codes中键为416的所有城市
pair<multimap<int,string>::iterator,multimap<int,string>::iterator> range = codes.equal_range(416);
// 定义指向multimap类型的对象中元素的迭代器
std::multimap<int,string>::iterator it;
for(it = range.first; it != range.second; ++it)
cout << (*it).second <<endl;
// 可以使用自动类型推断简化代码
auto range = codes.equal_range(416);
for(auto it = range.first; it != range.second; ++it)
cout << (*it).second <<endl;
函数对象(函数符)是可以以函数方式与()
结合使用的任意对象。函数名、指向函数的指针、重载了()
运算符的类对象都可以当做函数符使用。
使用函数符f
的函数,会响应得调用f()
。
可以使用类将多参数函数转换成单参数形式。