C++程序员应了解的那些事(91)C++容器之swap()函数的几点说明

本文详细分析了C++中swap函数对vector、array和string容器进行操作时的不同行为。对于vector,swap仅交换内部数据结构,不改变元素值,但保持迭代器有效性;而对于array,swap会交换元素值,时间复杂度与元素数量成正比;string特殊情况,swap可能导致迭代器、引用和指针失效,因字符串存储的动态特性。
摘要由CSDN通过智能技术生成

写在前面:
1、使用范围for遍历容器的每个元素,需要使用auto& it引用元素的同一块内存空间,不要使用auto it因为范围for的原型就是容器的迭代器遍历元素,将迭代器所指向的元素值然后拷贝给it,所以it又是栈上的一块内存空间了。建议使用引用类型,若不需要修改则写成const auto &it,需要修改写出auto &it。

2、关于array的swap的两个数组的相同类型是指容器所装的元素类型一致,还要元素的个数相同。

(一)swap操作交换两个相同类型的容器的内容,一般的容器(除array外),交换两个容器内容的操作会保证非常快,因为并没有交换元素本身,而只是交换了两个容器的内部数据结构!

注:这里交换两个容器的内部数据结构是指交换容器中各元素的内存地址,并不是交换各个元素变量所存储的值。除string外,swap使用之后指向容器的指针、引用和迭代器均有效(即开始指向哪个元素,在swap之后这个指针、引用和迭代器依然指向该元素)。

测试代码如下:

void test1()
{
    vector<int> v1 = { 1,2,3 };
    vector<int> v2 = { 4,5,6,7,8,9 };
    auto it1 = v1.begin();
    auto it2 = v2.begin();
    cout << "交换前迭代器it1指向的元素为:" << *it1 << endl;
    cout << "交换前迭代器it2指向的元素为:" << *it2 << endl;
    cout << "交换前v1每个元素的地址和值为:";
    for (const auto &it : v1)
    {
        cout << &it << " " << it << " ";
    }

    cout << "\n交换前v2每个元素的地址和值为:";
    for (const auto &it : v2)
    {
        cout << &it << " " << it << " ";
    }
    swap(v1, v2);
    cout << endl << endl;
    cout << "交换后迭代器it1指向的元素为:" << *it1 << endl;
    cout << "交换后迭代器it2指向的元素为:" << *it2 << endl;
    cout << "交换后v1每个元素的地址和值为:";
    for (const auto &it : v1)
    {
        cout << &it << " " << it << " ";
    }
    cout << "\n交换后v2每个元素的地址和值为:";
    for (const auto &it : v2)
    {
        cout << &it << " " << it << " ";
    }
    
    cout << endl;
    system("pause");
    return 0;
}

运行结果如下:

       可以看到,交换的是整个的内部数据结构,各元素(各地址)所存储的值并没有发生改变,只是这些元素(地址)已经属于不同的容器了。所以仅仅是交换了两个容器中元素的内存地址。所以swap操作后,指向容器内部的迭代器、引用和指针都任然有效,原来绑定的是哪个元素现在绑定的还是哪个元素。

(二)而swap两个array则真正交换了各个元素的值!

测试代码如下:

void test2()
{
    array<int,3> a1{ 1,2,3 };
    array<int,3> a2{ 4,5,6,};
    auto it1 = a1.begin();
    auto it2 = a2.begin();
    cout << "交换前迭代器it1指向的元素为:" << *it1 << endl;
    cout << "交换前迭代器it2指向的元素为:" << *it2 << endl;
    
    cout << "交换前a1每个元素的地址和值为:";
    for (int i = 0; i < 3; ++i)
    {
        cout << &a1[i] << " " << a1[i] << " ";
    }
    cout << "\n交换前a2每个元素的地址和值为:";
    for (int i = 0; i < 3; ++i)
    {
        cout << &a2[i] << " " << a2[i] << " ";
    }

    swap(a1, a2);
    cout << endl << endl;
    cout << "交换后迭代器it1指向的元素为:" << *it1 << endl;
    cout << "交换后迭代器it2指向的元素为:" << *it2 << endl;
    cout << "交换后a1每个元素的地址和值为:";
    for (int i = 0; i < 3; ++i)
    {
        cout << &a1[i] << " " << a1[i] << " ";
    }
    cout << "\n交换后a2每个元素的地址和值为:";
    for (int i = 0; i < 3; ++i)
    {
        cout << &a2[i] << " " << a2[i] << " ";
    }
}

运行结果如下:

       可以看到,交换后两个array交换了各个元素的值,即容器中所存的各个元素的内存地址并没有交换,只是交换了相应位置的元素的值,所以说swap两个array所需的时间和array中元素的数目成正比。同时swap操作后指向容器内部的迭代器、引用和指针都任然有效,原来绑定的是哪个元素现在绑定的还是哪个元素,只不过对应的元素值已经进行了交换。

(三)和其它容器不同的是,对string调用swap会导致迭代器、引用和指针失效。因为string存储的是字符串,在string变量中真正存储字符串的是一个叫_Ptr的指针,它指向string所存储的字符串首地址,而字符串并没有固定地址,而是存储在一个临时内存区域中,所以当字符串发生改变时,会发生内存的重新分配,所以会导致迭代器、引用和指针失效。

测试代码:

void test3()
{
    string s1{ "123" };
    string s2{ "45678" };
    auto it1 = s1.begin();
    auto it2 = s2.begin();
    cout << "交换前迭代器it1指向的元素为:" << *it1 << endl;
    cout << "交换前迭代器it2指向的元素为:" << *it2 << endl;
    swap(s1, s2);
    cout << endl << endl;
    cout << "交换后迭代器it1指向的元素为:" << *it1 << endl;
    cout << "交换后迭代器it2指向的元素为:" << *it2 << endl;
}

swap之前的各变量内存窗口:

swap之后的发生编译错误,显示迭代器已经失效了,效果图如下:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值