最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解C++ STL中vector擴(kuò)容機制

 更新時間:2024年03月28日 09:51:47   作者:number=10086  
vector是表示可以改變大小的數(shù)組的序列容器,就像數(shù)組一樣,vector對其元素使用連續(xù)的存儲位置,這篇文章將給大家詳細(xì)介紹C++ STL中vector擴(kuò)容機制,文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下

vector是STL提供的動態(tài)數(shù)組,它會在內(nèi)部空間不夠用時動態(tài)的調(diào)整自身的大小,調(diào)整過程中會有大量的數(shù)據(jù)拷貝,為了減少數(shù)據(jù)拷貝的次數(shù)vector會在調(diào)整空間的時候盡量多申請一些空間,這些預(yù)留出的空間可以很大程度上減少拷貝的發(fā)生。

在windows環(huán)境中使用vs運行這段代碼

#include<iostream>
#include<vector>
using namespace std;
void fun(vector<int>&vec){
	vec.push_back(1);
    cout<<&vec[0]<<vec.size()<<" "<<vec.capacity()<<endl;
}
int main(){
    vector<int>vec;
    for(int i=0;i<10;i++) fun();
}

打印內(nèi)容依次為,首元素地址,已經(jīng)使用的空間,容器的容量

首先看push_back源碼,第一個拷貝版本,第二個移動版本,需要注意的是這里第二個不是萬能引用而是右值引用,下面看emplace_back代碼

void push_back(const _Ty& _Val) { // insert element at end, provide strong guarantee
        emplace_back(_Val);
    }

    void push_back(_Ty&& _Val) { // insert by moving into element at end, provide strong guarantee
        emplace_back(_STD move(_Val));
    }

emplace_back使用了可變參數(shù),并且對參數(shù)使用了萬能引用,從而使得可以在插入節(jié)點時調(diào)用對應(yīng)的構(gòu)造函數(shù),比如:vector<pair<int,int>>vec;vec.emplace_back(1,2);這么做可以很大程度上簡化代碼的書寫,同時還可以減少一次移動或是拷貝的過程,decltype(auto)這個沒什么說的根據(jù)返回值推導(dǎo)返回值類型。

回歸正題,執(zhí)行emplace_back的時候會判斷容量是否充足,size!=capacity的時候會直接加入元素,否則的話會調(diào)用_Emplace_reallocate函數(shù)進(jìn)行擴(kuò)容。

template <class... _Valty>
    decltype(auto) emplace_back(_Valty&&... _Val) {
        // insert by perfectly forwarding into element at end, provide strong guarantee
        auto& _My_data   = _Mypair._Myval2;
        pointer& _Mylast = _My_data._Mylast;
        if (_Mylast != _My_data._Myend) {
            return _Emplace_back_with_unused_capacity(_STD forward<_Valty>(_Val)...);
        }

        _Ty& _Result = *_Emplace_reallocate(_Mylast, _STD forward<_Valty>(_Val)...);
#if _HAS_CXX17
        return _Result;
#else // ^^^ _HAS_CXX17 ^^^ // vvv !_HAS_CXX17 vvv
        (void) _Result;
#endif // _HAS_CXX17
    }

下面看擴(kuò)容代碼,代碼有點長我直接在代碼上加注釋了

template <class... _Valty>
    pointer _Emplace_reallocate(const pointer _Whereptr, _Valty&&... _Val) {
        // reallocate and insert by perfectly forwarding _Val at _Whereptr
        _Alty& _Al        = _Getal();
        auto& _My_data    = _Mypair._Myval2;//使用的長度
        pointer& _Myfirst = _My_data._Myfirst;//容器開始的位置
        pointer& _Mylast  = _My_data._Mylast;//容器末尾

        _STL_INTERNAL_CHECK(_Mylast == _My_data._Myend); // check that we have no unused capacity

        const auto _Whereoff = static_cast<size_type>(_Whereptr - _Myfirst);//插入元素的位置,這個函數(shù)insert也有在用,所以插入的位置不一定在尾部
        const auto _Oldsize  = static_cast<size_type>(_Mylast - _Myfirst);//容器大小

        if (_Oldsize == max_size()) {//長度超過數(shù)組的最大長度時報錯
            _Xlength();
        }

        const size_type _Newsize     = _Oldsize + 1;
        const size_type _Newcapacity = _Calculate_growth(_Newsize);//調(diào)用擴(kuò)容函數(shù)

        const pointer _Newvec           = _Al.allocate(_Newcapacity);//申請新的空間
        const pointer _Constructed_last = _Newvec + _Whereoff + 1;//計算新的末尾
        pointer _Constructed_first      = _Constructed_last;

        _TRY_BEGIN
        _Alty_traits::construct(_Al, _Unfancy(_Newvec + _Whereoff), _STD forward<_Valty>(_Val)...);//在新的空間添加新的元素
        _Constructed_first = _Newvec + _Whereoff;
		//下面是根據(jù)插入元素的位置判斷如何拷貝
        if (_Whereptr == _Mylast) { // at back, provide strong guarantee
            _Umove_if_noexcept(_Myfirst, _Mylast, _Newvec);//移動,不能移動時拷貝
        } else { // provide basic guarantee
            _Umove(_Myfirst, _Whereptr, _Newvec);
            _Constructed_first = _Newvec;
            _Umove(_Whereptr, _Mylast, _Newvec + _Whereoff + 1);
        }
        _CATCH_ALL//拷貝出現(xiàn)異常的時候釋放對應(yīng)的內(nèi)容
        _Destroy(_Constructed_first, _Constructed_last);
        _Al.deallocate(_Newvec, _Newcapacity);
        _RERAISE;
        _CATCH_END

        _Change_array(_Newvec, _Newsize, _Newcapacity);//更新數(shù)組信息
        return _Newvec + _Whereoff;//偏移到新元素的地址
    }

下面看擴(kuò)展策略,傳入的_Newsize是_Oldsize + 1,_Max是容器最大容量一般是達(dá)不到的我試著輸出了一下我的環(huán)境下是4611686018427387903,可以看到正常情況下新的容量是以前的容量的1.5倍(不同編譯器的擴(kuò)容策略不一樣,g++中是2),當(dāng)新的容量還不夠的時候會轉(zhuǎn)而按需分配。

size_type _Calculate_growth(const size_type _Newsize) const {
        // given _Oldcapacity and _Newsize, calculate geometric growth
        const size_type _Oldcapacity = capacity();
        const auto _Max              = max_size();
        if (_Oldcapacity > _Max - _Oldcapacity / 2) {
            return _Max; // geometric growth would overflow
        }
        const size_type _Geometric = _Oldcapacity + _Oldcapacity / 2;
        if (_Geometric < _Newsize) {
            return _Newsize; // geometric growth would be insufficient
        }
        return _Geometric; // geometric growth is sufficient
    }

需要注意的是resize申請機制是按需分配的,當(dāng)新的容量大于舊的時候會更新容量大小,當(dāng)新的大小大于舊的容量的時候只會刪除多余的元素而不會進(jìn)行拷貝,數(shù)組容量不變不會釋放數(shù)組空間但是多余的元素會被析構(gòu)掉,詳情運行下面這段代碼。

#include<iostream>
#include<vector>
using namespace std;

class A {
public:
    A(){}
    int* a = new int(1);
    ~A() { cout << this << "析構(gòu)"<<endl; }
};

void fun(vector<A>& vec) {
    vec.push_back(A());
    cout << &vec[0] << " " << vec.size() << " " << vec.capacity() << endl;
}
int main() {
    vector<A>vec;
    for (int i = 0; i < 10; i++) fun(vec);
    vec.resize(5);
    cout << vec.capacity()<<endl;
}

以上就是詳解C++ STL中vector擴(kuò)容機制的詳細(xì)內(nèi)容,更多關(guān)于C++ STL vector擴(kuò)容的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C語言數(shù)據(jù)結(jié)構(gòu)與算法之排序總結(jié)(二)

    C語言數(shù)據(jù)結(jié)構(gòu)與算法之排序總結(jié)(二)

    這篇文章住要介紹的是選擇類排序中的簡單、樹形和堆排序,歸并排序、分配類排序的基數(shù)排序,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2021-12-12
  • c++難以發(fā)現(xiàn)的bug(有趣)

    c++難以發(fā)現(xiàn)的bug(有趣)

    這篇文章主要介紹了c++難以發(fā)現(xiàn)的bug(有趣)的相關(guān)資料,需要的朋友可以參考下
    2017-10-10
  • C++模板編程特性之移動語義

    C++模板編程特性之移動語義

    首先,移動語義和完美轉(zhuǎn)發(fā)這兩個概念是在C++的模板編程的基礎(chǔ)上,新增的特性,主要是配合模板來使用。本篇會從C++的值類型,到移動拷貝與移動賦值來理解移動語義與完美轉(zhuǎn)發(fā)
    2022-08-08
  • C++深入探究list的模擬實現(xiàn)

    C++深入探究list的模擬實現(xiàn)

    list相較于vector來說會顯得復(fù)雜,它的好處是在任意位置插入,刪除都是一個O(1)的時間復(fù)雜度,本文主要介紹了C++中List的模擬實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • C語言 完整游戲項目坦克大戰(zhàn)詳細(xì)代碼

    C語言 完整游戲項目坦克大戰(zhàn)詳細(xì)代碼

    《坦克大戰(zhàn)》以二戰(zhàn)坦克為題材,既保留了射擊類游戲的操作性,也改進(jìn)了射擊類游戲太過于復(fù)雜難玩的高門檻特點,集休閑與競技于一身。經(jīng)典再度襲來,流暢的畫面,瘋狂的戰(zhàn)斗,讓玩家再次進(jìn)入瘋狂坦克的世界。玩家的目標(biāo)是控制坦克躲避危險,消滅掉所有的敵人即可進(jìn)入下一關(guān)
    2021-11-11
  • C語言對冒泡排序進(jìn)行升級介紹

    C語言對冒泡排序進(jìn)行升級介紹

    大家好,本篇文章主要講的是C語言對冒泡排序進(jìn)行升級介紹,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • 基于C語言實現(xiàn)高級通訊錄的示例代碼

    基于C語言實現(xiàn)高級通訊錄的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用C語言實現(xiàn)一個高級通訊錄的功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,需要的小伙伴可以參考一下
    2023-01-01
  • C++ std::async的使用總結(jié)

    C++ std::async的使用總結(jié)

    這篇文章主要介紹了C++ std::async的使用總結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • C++實現(xiàn)raw_input的方法

    C++實現(xiàn)raw_input的方法

    這篇文章主要介紹了C++實現(xiàn)raw_input的方法,通過C++來實現(xiàn)Python中發(fā)raw_input的方法,非常具有實用價值,需要的朋友可以參考下
    2014-10-10
  • C語言中數(shù)組作為函數(shù)的參數(shù)以及返回值的使用簡單入門

    C語言中數(shù)組作為函數(shù)的參數(shù)以及返回值的使用簡單入門

    這篇文章主要介紹了C語言中數(shù)組作為函數(shù)的參數(shù)以及返回值的使用簡單入門,這里以一維數(shù)組作為基本條件進(jìn)行例子講解,需要的朋友可以參考下
    2015-12-12

最新評論

兴海县| 安化县| 房山区| 吉林市| 铁力市| 寿光市| 成武县| 搜索| 定南县| 芦溪县| 黑龙江省| 孙吴县| 缙云县| 彩票| 灵山县| 通海县| 岚皋县| 永嘉县| 洛隆县| 临猗县| 应城市| 环江| 璧山县| 砚山县| 成安县| 通许县| 许昌县| 古丈县| 水富县| 宁河县| 临泽县| 德令哈市| 无极县| 巴林右旗| 巢湖市| 游戏| 彰化县| 商河县| 永新县| 海伦市| 万荣县|