swap与assign

表 9.4中列出的与赋值相关的运算符可用于所有容器。赋值运算符将其左边容器中的全部元素替换为右边容器中元素的拷贝:

c1 = c2;           // 将c1的内容替换为c2中元素的拷贝
c1 = {a, b, c};    // 赋值后,c1大小为3

第一个赋值运算后,左边容器将与右边容器相等。如果两个容器原来大小不同,赋值运算后两者的大小都与右边容器的原大小相同。

第二个赋值运算后,c1的size变为 3,即花括号列表中值的数目。

与内置数组不同,标准库 array 类型允许赋值。赋值号左右两边的运算对象必须具有相同的类型:

array<int, 10> a1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
array<int, 10> s2 = {0};   // 所有元素值均为0
a1 = a2;	               // 替换a1中的元素
a2 = {0};                  // 错误:不能将一个花括号列表赋予数组

由于右边运算对象的大小可能与左边运算对象的大小不同,因此 array 类型不支持 assign,也不允许用花括号包围的值列表进行赋值

image-20210125142022356

使用assign(仅顺序容器)

赋值运算符要求左边和右边的运算对象具有相同的类型。它将右边运算对象中所有元素拷贝到左边运算对象中。

顺序容器(array除外)还定义了一个名为 assign的成员,允许我们从一个不同但相容的类型赋值,或者从容器的一个子序列赋值。

assign 操作用参数所指定的元素(的拷贝)替换左边容器中的所有元素。

例如,我们可以用 assgin 实现将一个 vector 中的一段 char*值赋予一个list 中的 string:

list<string> names;
vector<const char*> oldstyle;
names = oldstyle;  // 错误:容器类型不匹配
// 正确:可以将const char*转换为string
names.assign(oldstyle.cbegin(), oldstyle.cend());

这段代码中对 assign 的调用将 names 中的元素替换为迭代器指定的范围中的元素的拷贝。assign 的参数决定了容器中将有多少个元素以及它们的值都是什么。

assign 的第二个版本接受一个整型值和一个元素值。它用指定数目且具有相同给定值的元素替换容器中原有的元素:

// 等价于slist1.clear()
// 后跟slist.insert(slist1.begin(), 10, "Hiya");
list<string> slist1(1);      // 一个元素,为空string
slist1.assign(10, "Hiya!");  // 10个元素,每个都是"Hiya!"

使用swap

swap操作交换两个相同类型容器的内容,调用swap后,两个容器的内容会交换。

vector<string> svec1(10);
vector<string> svec2(24);
swap(svec1, svec2);

调用swap后,svec1将包含24个string元素,svec2将包含10个string。除array外,交换两个容器内容的操作保证会很快——元素本身并未交换,swap 只是交换了两个容器的内部数据结构

元素不会被移动的事实意味着,除 string 外,指向容器的迭代器、引用和指针在 swap操作之后都不会失效。它们仍指向 swap操作之前所指向的那些元素。

但是,在swap之后,这些元素已经属于不同的容器了。

例如,假定iter在swap之前指向svec1[3]的string,那么在swap之后它指向svec2[3]的元素。与其他容器不同,对一个string调用 swap 会导致迭代器、引用和指针失效

与其他容器不同,swap两个array会真正交换它们的元素。因此,交换两个array所需的时间与 array 中元素的数目成正比

因此,对于array,在 swap操作之后,指针、引用和迭代器所绑定的元素保持不变,但元素值已经与另一个 array 中对应元素的值进行了交换

在新标准库中,容器既提供成员函数版本的 swap,也提供非成员版本的 swap。而早期标准库版本只提供成员函数版本的 swap。非成员版本的 swap在泛型编程中是非常重要的。统一使用非成员版本的 swap 是一个好习惯。

posted @ 2021-01-25 14:39  DearLeslie  阅读(468)  评论(0编辑  收藏  举报