c++ 顺序容器——初始化、赋值与swap

1.STL顺序容器概述

c++ 标准模板库中的顺序容器包含:

vector 可变大小数组,支持快速随机访问,在除尾部外插入删除数据会很慢
deque 双端队列,支持快速随机访问,在头尾位置插入/删除数据很快
list 双向链表,只支持双向顺序访问,在任何位置插入删除都很快
forward_list 单向链表,支持单向顺序访问
array 固定大小数组。支持快速随机访问,不能添加或删除元素

我们根据以上特点来实际选择需要的容器。

2.初始化

2.1每个顺序容器都有一个默认构造函数

vector<int> c;

构造一个空的vector对象

2.2 拷贝构造函数

调用拷贝构造函数时类型必须匹配

vector<int> a = {0,1,2};
vector<int> b(a);//正确
vector<string> c(a);//错误
list<int> d(a);//错误

2.3 迭代器范围初始化

容器接受两个迭代器作为参数,拷贝这个迭代器范围(左闭右开)的元素,此时不要求容器类型相同,只要求新容器与旧容器中元素相容

vector<int> a = {0,1,2,3};
vector<double> b(++a.begin(),a.end());//正确,b为{1.0,2.0,3.0}

2.4 列表初始化

vector<string> a = {"l","l","z"};

除了array以外列表初始化还隐式指定了容器的大小为列表中元素个数。

2.5 与顺序容器大小相关的构造函数

除array以外,顺序容器还提供一个以容器大小和一个(可选的)初始值为参数的构造函数,如果元素类型是内置类型或具有默认构造函数,可以只提供一个容器大小的参数,如果元素类型没有默认构造函数则必须还要指定一个显式的元素初始值。

vector<int> a(10,1);//容器大小为10,初始化为10个值为1的元素
list<string> b(2,"lz");

2.6 array的构造

与内置数组一样,array大小也是其类型的一部分,定义时除了指定元素类型还要指定容器大小

array<int,3> a;//保存3个int类型元素的数组

上述其他容器的构造函数都显式或隐式地确定了容器的大小所以对array都不适用,arrary的默认构造函数构造的也不是一个非空的对象,如果我们用列表初始化array对象,列表元素的个数要小于等于array对象定义时的大小,并初始化靠前的元素

array<int,3> a;//默认构造函数,3个0
array<int,10> b = {1,2,3};//b的前三个元素为1,2,3,后七个元素为0

此外虽然对于内置数组类型不能拷贝或做对象赋值操作,但是array却可以,array要求拷贝的旧容器与新容器类型相同(包括容器大小)

array<int,3> a = {1,2,3};
array<int,3> b(a);//正确
array<int,3> c = a;//正确
array<int,4> d(a);//错误,类型不匹配

3.赋值与swap

stl支持的容器运算(这里的"="是赋值运算符,不是拷贝构造运算符)

c1 = c2 将c1中的元素替换为c2中的拷贝,c1与c2必须具有相同的类型
c = {a,b,c...} 将c中元素替换为列表中元素的拷贝(array不适用)
swap(c1,c2)/c1.swap(c2) 交换c1,c2中元素,必须具有相同类型
seq.assign(b,e) 将b中的元素替换为迭代器b到e范围内的元素,b和e不能指向seq中的元素(不适用于array)
seq.assign(il) 将seq中的元素替换为初始化列表il中的元素(array不适用)
seq.assign(n,t) 将seq中的元素替换为n个值为t的元素

赋值运算符左边的对象将会是右边对象的拷贝,赋值运算符和assign赋值对内置类型逐bit拷贝,对有拷贝构造函数的类型调用其拷贝构造函数。
赋值运算符要求左右两边具有相同类型,而在顺序容器(array除外)中assign成员允许我们从一个不同但相容的类型赋值。

vector<char*> a;
list<string> b;
b.assign(a.begin(),a.end());//正确

由于旧对象会被先销毁,所以迭代器参数不能是旧对象的迭代器。
除array以外swap操作两个容器内部的数据结构元素本身并未交换,所以执行起来会很快,swap之后两个容器的迭代器还是指向原来的元素,并不发生变化。
而array调用swap会真正交换它们的元素,因此交换时间与其中元素个数成正比,而迭代器也还是指向原来的地址,但是存的值发生了变化。
c++标准提供成员版本的swap和非成员版本的swap,非成员版本的swap对于泛型编程是非常重要的,统一使用非成员版本的swap是一个好习惯。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容