赞
踩
容器:特定类型对象的集合
顺序容器类型
某些类没有默认构造函数,我们可以定义一个保存这种类型对象的容器,但我们在构造这种容器时不能只传递给它一个元素数目参数:
//假设noDefault是一个没有默认构造函数的类型
vector<noDeault> v1(10, init);//正确,提供了元素初始化器
vector<noDefault> v2(10); //错误,必须提供一个元素初始化器
容器操作:
end():指向尾元素之后的位置,因此迭代器范围[begin, end)。end可以与begin指向相同的位置,但不能指向begin之前的位置。
反向迭代器是一种反向遍历容器的迭代器,与正向迭代器相比,各种操作的含义也都发生了颠倒。如对于一个反向迭代器执行++操作,会得到上一个元素。
显示使用类名使用相应类型:
//iter是通过list<string>定义的一个迭代器类型
list<string>::iterator iter;
//count是通过vector<int>定义的一个difference_type类型
vector<int>::difference_type count;
将一个容器初始化为另一个容器的拷贝:
当一个容器初始化另一个容器的拷贝时,两个容器的容器类型和元素类型必须相同
list<string> authors ={"Milton","Shakespeare","Austen"};
vector<const char*> articles = {"a", "an", "the"};
list<string> list2(authors); //正确:类型匹配
deque<string> authList(authors);//错误:容器类型不匹配
vector<string> words(articles); //错误:容器类型必须匹配
//正确:可以将const char* 元素转换为string
forward_list<string> words(articles.begin(), articles.end());
//拷贝元素,直到(但不包括)it指向的元素
deque<string> authList(authors.begin(), it);
标准库array具有固定大小:
当定义一个array时,除了指定元素类型,还要指定容器大小:
array<int, 42> //保存为42个int的数组
array<string, 10>//保存为10个string的数组
//使用array类型时需要同时指定元素类型和大小
array<int, 10>::size_type i; //数组类型包括元素类型和大小
array<int>::size_type j; //错误:array<int>不是一个类型
虽然我们不能对内置数组进行拷贝和对象赋值操作,但array并无此限制。
int digs[10] = {0,1,2,3,4,5,6,7,8,9};
int cpy[10] = digs;//错误:内置数组不支持拷贝或赋值
array<int,10> digits = {0,1,2,3,4,5,6,7,8,9};
array<int,10> copy = digits;//正确:只要数组类型匹配即合法
使用assign(仅顺序容器)
assign操作用参数所指定的元素(的拷贝)替换左边容器中的所有元素。
list<string> names;
vector<const char*> oldstyle;
names = oldstyle;//错误:容器类型不匹配
//正确:可以将const char* 转换成string
names.assign(oldstyle.cbegin(), oldstyle.cend())
assign的第二个版本接受一个整型值和一个元素值。它用指定数目且具有相同给定的元素替换容器中原有的元素:
//等价于slist1.clear()
//后跟slist1.insert(slist1.begin(), "Hiya!");
list<string> slist1(1); //一个元素,为空string
slist1.assign(10,"Hiya!"); //10个元素, 每个都是"Hiya!“
使用swap:交换两个相同类型容器的内容。调用swap之后,两个容器内的元素将会交换:
vector<string> svec1(10);
vector<string> svec2(24);
swap(svec1, svec2);
使用push_front:
list<int> ilist;
//将元素添加到ilist开头
for (size_t ix=0; ix!=4;++ix)
ilist.push_back(ix);
//ilist保存序列3,2,1,0
insert函数将元素插入到迭代器所指定的位置之前。
slist.insert(iter, "Hello!"); //将"Hello“添加到iter之前的位置
vector<string> svec;
list<string> slist;
//等价于调用slist.insert(iter, "Hello!")
slist.insert(slist.begin(),"Hello!");
//vector不支持push_front,但我们可以插入到begin()之前
svec.insert(svec.begin(), "Hello!");
插入范围元素:
svec.insert(svec.end(), 10, "Anna");
//将10个元素插入到svec的末尾,并将所有元素初始化为string "Anna"
vector<string> v={"quasi", "simba", "frollo","scar"};
//将v的最后两个元素添加到slist的开始位置
slist.insert(slist.begin(), v.end()-2, v.end());
slist.insert(slist.end(),{"these", "words", "will",
"go","at","the","end"});
//运行时错误:迭代器表示要拷贝的范围,不能指向与目的位置相同的容器
slist.insert(slist.begin(), slist.begin(), slist.end());
使用insert的返回值:通过使用insert的返回值,可以在容器中一个特定位置反复插入元素
list<string> lst;
auto iter = lst.begin();
while(cin>>word)
iter = lst.insert(iter,word);//等价于调用push_front
使用emplace操作:emplace_front emplace和emplace_back,这些操作分别对应push_front、insert和push_back,允许我们将元素放置在容器头部、一个指定位置之前或容器尾部。
调用push或Insert成员函数时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中。当我们调用一个emplace成员函数时,则是将参数传递给元素类型的构造函数。emplace成员使用这些参数在容器管理的内存空间中直接构造函数。
//在c的末尾构造一个Sales_data对象
//使用三个参数的Sales_data构造函数
c.emplace_back("978-33743673",25,15.99);
//错误:没有接受三个参数的push_back版本
c.push_back("978-33743673",25,15.99);
//正确:创建一个临时的Sales_data对象传递给push_back
c.push_back(Sales_data("978-33743673",25,15.99));
在调用emplace_back时,会在容器管理的内存空间中直接创建对象。而调用push_back则会创建一个局部临时对象,并将其压入容器中。
emplace函数的参数根据元素类型而变换,参数必须与元素类型的构造函数相匹配:
//iter指向c中一个元素,其中保存了Sales_data元素
c.emplace_back();//使用Sales_data的默认构造函数
c.emplace(iter, "999-9999999");//使用Sales_data(string)
//使用Sales_data的接受一个ISBN、一个count和一个price的构造函数
c.emplace_front("999-99999",25,25.9);
emplace函数在容器中直接构造元素。传递给emplace函数的参数必须与元素类型的构造函数相匹配。
包括array在内的每个顺序容器都有一个front成员函数,而除forward_list之外的所有顺序容器都有一个back成员函数。这两个操作分别返回首元素和尾元素的引用:
//在解引用一个迭代器或调用front或back之前检查是否有元素
if(!c.empty()){
//val和val2是c中第一个元素值的拷贝
auto val = *c.begin(), val2 = c.front();
//val3和val4是c中最后一个元素值的拷贝
auto last = c.end();
auto val3 = *(--last);//不能递减forward_list迭代器
auto val4 = c.back();
}
访问成员函数返回的是引用:在容器中访问元素的成员函数(front、back、下标和at ) 返回的都是引用。如果容器是一个const对象,则返回值是const的引用。
if(!c.empty()){
c.front() = 42; //将42赋予c中的第一个元素
auto &v = c.back(); //获得指向最后一个元素的引用
v = 1024; //改变c中的元素
auto v2 = c.back(); //v2不是一个引用,它是c.back()的一个拷贝
v2 = 0;未改变c中元素
}
如果我们希望确保下标是合法的,可以使用at成员函数。at成员函数类似下标运算符,如果下标越界,at会抛出一个out_of_range异常。
成员函数erase从容器中指定位置删除元素:
list<int> lst={0,1,2,3,4,5,6,7,89};
auto it=lst.begin();
while(it!=lst.end())
if(*it%2)
it = lst.erase(it);
else
++it;
//删除两个迭代器表示的范围内的元素
//返回指向最后一个被删元素之后位置的迭代器
elem1 = slist.erase(elem1, elem2); //调用后,elem1==elem2
forward_list操作:
从forward_list中删除元素:
forward_list<int> flst = {0,1,2,3,4,5,6,7,8,9};
auto prev = flst.before_begin(); //表示flst的"首前元素"
auto curr = flst.begin(); //表示flst中的第一个元素
while(curr!=flst.end()){
if(*curr%2)
curr = flst.erase_after(prev);
else{
prev = curr;//移动迭代器curr,指向下一个元素,prev指向curr之前的元素
++curr;
}
}
改变容器大小resize():如果当前大小小于所要求的大小,容器后部的元素会被删除;如果当前大小小于新大小,会将新元素添加到容器后部。
编写改变容器的循环:
vector<int> vi={0,1,2,3,4,5,6,7,8,9};
auto iter=vi.begin();//调用begin而不是cbegin,因为要改变vi
while(iter!=vi.end()){
if(*iter % 2){
iter = vi.insert(iter,*iter);//复制当前元素
iter += 2;//向前移动迭代器,跳过当前元素以及插入到它之前的元素
}else
iter = vi.erase(iter); //删除偶数元素
//不应向前移动迭代器,iter指向我们删除元素之后的元素
}
不要保存end返回的迭代器:此代码会导致无线循环。问题在于我们将end操作返回的迭代器保存在一个名为end的局部变量中。在循环体中,我们向容器中添加了一个元素,这个操作使保存在end中的迭代器失效了。这个迭代器不再指向任何元素或是v中尾元素之后的位置。
//此循环的行为是未定义的
auto begin = v.begin(), end = v.end();//保存尾迭代器的一个坏主意
while(begin != end){
//插入新值,对begin重新赋值,否则的话它会失效
++begin;//向前移动begin,因为我们想在此元素之后插入元素
begin = v.insert(begin, 42); //插入新值
++begin;//向前移动begin跳过刚刚加入的元素
}
如果在一个循环中插入/删除 deque, string或vector中的元素,不要缓存end返回的迭代器。
必须在每次插入操作后重新调用end(),而不能在循环开始前保存它返回的迭代器。
//安全的方法:在每个循环步添加/删除元素后都重新计算end
while(begin!=v.end()){
++begin;
begin = v.insert(begin, 42);
++begin;
}
管理容量的成员函数:
capacity和size: 容器中的size是指它已经保存的元素的数目;而capacity则是在不分配新的内存空间的前提下它最多可以保存多少元素。可以调用shrink_to_fit来要求vector将超出当前大小的多余内存退回给系统。
通常从一个const char*创建string时,指针指向的数组必须以空字符结尾,拷贝操作遇到空字符时停止。
substr操作:返回原始string的一部分或全部的拷贝。
string s("hello world");
string s2=s.substr(0,5);//s2=hello
string s3=s.substr(6); //s3=world
string s4=s.substr(6,11);//s4=world
string s5=s.substr(12);//抛出一个out_of_range异常
如果开始位置超过了string的大小,则substr函数抛出一个out_of_range异常。如果开始位置加上技术支持大于string的大小,则substr会调整计数值,只拷贝到string的末尾。
改变string: assign、insert和erase操作。
string 搜索:
compare函数:
数值转换:
栈适配器:
队列适配器:
begin和cbegin之间的区别:
vector初始化方式:
为什么list或array没有capacity成员函数?
为什么list或array没有capacity成员函数?
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。