利用swap()收缩内存空间(C++)

万恶之源-vector

众所周知,vector会根据输入数据自动分配内部空间,无需人为指定大小,这当然方便我们日常使用,但自动分配也就意味着一定程度上的不可控,在某些情况下极易造成内存空间的浪费,比如下面这段代码:

    vector<int>v;
    for (int i = 0; i < 1000000; i++)
    {
        v.push_back(i);
    }

这段代码的实际作用其实是向vector容器中插入了100万个数,为了更加直观的展现vector自动分配空间的坑,可以利用vectorcapacity()成员函数可以返回它的实际存储空间大小(自动开辟的空间),以及swap()返回容器中元素个数,在第一段代码之后输出vector容量:

    vector<int>v;
    for (int i = 0; i < 1000000; i++)
    {
        v.push_back(i);
    }
    cout << "v当前容量:" << v.capacity() << endl;
    cout << "v当前大小:" << v.size() << endl;

运行结果为:

file

可以看到自动分配的空间与实际容量其实是相近的,在这种情况下并不存在空间浪费。
但是,如果在插入100万个元素之后,如果再使用vectorresize()成员函数,resize()的作用是重新指定vector大小,当重新指定的大小比原来的更大时,并不会造成内存浪费,但如果比原来的更小,情况就不一样了,来看下段代码演示:

    vector<int>v;
    for (int i = 0; i < 1000000; i++)
    {
        v.push_back(i);
    }

    cout << "v当前容量:" << v.capacity() << endl;
    cout << "v当前大小:" << v.size() << endl;

    cout << "重新制定大小后:" << endl;

    v.resize(3);    //重新指定大小
    cout << "v当前容量:" << v.capacity() << endl;//大小变小,容量不变
    cout << "v当前大小:" << v.size() << endl;

运行结果为:

file

你会发现resize()虽然将vector大小指定为了3,但实际占用空间还是原来的一百多万!这就造成了严重了内存空间浪费,甚至哪怕使用clear()清空vector,实际空间也不会发生任何变化!

内存救星-swap()

要想解决这个问题,其实不需要销毁vector重新实例化,只需要利用自带的swap()成员函数即可,swap()的函数原型是void swap ( vector<T,Allocator>& vec );作用就是交换两个vector,使用下面这段代码来实现内存空间收缩:

    vector<int>v;
    for (int i = 0; i < 1000000; i++)
    {
        v.push_back(i);
    }

    cout << "v当前容量:" << v.capacity() << endl;
    cout << "v当前大小:" << v.size() << endl;

    cout << "重新指定大小后:" << endl;

    v.resize(3);    //重新指定大小
    cout << "v当前容量:" << v.capacity() << endl;//大小变小,容量不变
    cout << "v当前大小:" << v.size() << endl;

    vector<int>(v).swap(v);

    cout << "利用swap()收缩内存空间后:" << endl;
    cout << "v当前容量:" << v.capacity() << endl;
    cout << "v当前大小:" << v.size() << endl;

此时的运行结果:

file

浅扒一下底层

仔细观察下面这行代码:

    vector<int>(v).swap(v);

这段代码“直译”过来就是:

  1. 新建了一个匿名的vector
  2. 将匿名vector与原vector交换(也就是实例化的v)

其实swap()的底层原理就是将两个容器的指针互换(但迭代器指向未交换,切记!),将v的指向从那“一百多万”的空间变成了新的匿名函数的“3”的空间,又因为匿名对象使用完就会被自动释放,因此也就把原vector开辟的空间释放干净了,也就不存在内存浪费的问题了。
为方便理解,画个图演示下:

file

swap()的坑

虽然swap()实现了两个容器指针互换,但并未交换其迭代器,也就是说:如果在swap()之前就定义了迭代器,则交换后,虽然容器名的指向已经变了,但迭代器还是指向原内存空间,此时再对迭代器解引用将会得到错误的值,例如下段代码:

    vector<int>v1 = { 1,2,3 };
    auto it1 = v1.begin();

    vector<int>v2 = { 4,5,6 };
    auto it2 = v2.begin();

    v1.swap(v2);

    cout << "*it1=" << *it1 << endl;
    cout << "*it2=" << *it2 << endl;

实际运行结果为:

file

可以看到虽然已经执行了swap()函数,此时v1v2的指向已经发生交换,但it1it2还是指向原来的内存空间,此时对其解引用将无法得到正确的结果。

解决办法也很简单,在swap()交换后,重新给迭代器赋一下值,让它们更新到正确的地址,参考下段代码:

    vector<int>v1 = { 1,2,3 };
    auto it1 = v1.begin();

    vector<int>v2 = { 4,5,6 };
    auto it2 = v2.begin();

    v1.swap(v2);

    //更新指向
    it1 = v1.begin();
    it2 = v2.begin();

    cout << "*it1=" << *it1 << endl;
    cout << "*it2=" << *it2 << endl;

此时运行结果为:

file


参考文章:https://blog.csdn.net/qq_43684922/article/details/96569413

本文作者:小小黑
本文链接:https://lonelyenderman.top/archives/852
版权声明:本站采用 BY-NC-SA 进行许可。转载请注明出处!
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(*^▽^*)
 ̄﹃ ̄
(╯‵□′)╯︵┴─┴
(~ ̄▽ ̄)~
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
( ͡° ͜ʖ ͡°)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
つ﹏⊂
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
(´▽`ʃ♡ƪ)
w(゚Д゚)w
(๑•̀ㅂ•́)و✧
(#`O′)
凸(艹皿艹 )
o(≧口≦)o
≡ω≡
(*/ω\*)
○| ̄|_
(⊙ˍ⊙)
Σ(っ °Д °;)っ
o( ̄ヘ ̄o#)
<( ̄︶ ̄)>
(。・∀・)ノ゙
(o゜▽゜)o☆
╥﹏╥
ヾ(´・ω・`)ノ
😂
😀
😅
😊
🙂
😍
😘
😜
😝
😏
😒
🙄
😳
😔
😫
😱
😭
😶
🌚
😣
🤨
😣
🤐
😪
🤤
🥵
🤮
😨
😱
😓
🤬
👴
🤡
🙈
💊
🙏
🤺
💩
👻
🙌
🖕
👍
👫
👌
🙏
👀
🐒
🔪
Source: github.com/zhheo/Sticker-Heo
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
Heo
花!
上一篇
下一篇