成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

【C++】vector的使用及其模擬實現(xiàn)-創(chuàng)新互聯(lián)

一、vector 的使用

vector 是我們學(xué)習(xí)的第一個真正的 STL 容器,它接口的使用方式和 string 有一點點的不同,但大部分都是一樣的,所以這里我們就只演示其中一些接口的使用,大家如果有疑惑的地方直接在 cplusplus 是上面查看對應(yīng)的文檔即可。

成都創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供巴馬網(wǎng)站建設(shè)、巴馬做網(wǎng)站、巴馬網(wǎng)站設(shè)計、巴馬網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、巴馬企業(yè)網(wǎng)站模板建站服務(wù),10年巴馬做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。1、構(gòu)造函數(shù)

vector 提供了四種構(gòu)造方式 – 無參構(gòu)造、n 個 val 構(gòu)造、迭代器區(qū)間構(gòu)造以及拷貝構(gòu)造:image-20221130162427586

其中構(gòu)造函數(shù)的最后一個參數(shù) alloc 是空間配置器,它和內(nèi)存池有關(guān),作用是提高空間分配的效率;我們?nèi)粘J褂脮r不用管這個參數(shù),使用它的缺省值即可,但是可能有極少數(shù)的人想要用自己實現(xiàn)的空間配置器來代替 STL 庫提供的,所以留出了這一個參數(shù)的位置。image-20221130163906531

需要注意的是,迭代器區(qū)間構(gòu)造是一個函數(shù)模板,即我們可以用其他類來構(gòu)造 vector 對象:image-20221130164323555

同時,上面還有一個非常重要的細(xì)節(jié):

在 n 個 val 的構(gòu)造中,val 的缺省值是 T 的匿名對象,該對象使用 T 的默認(rèn)構(gòu)造來初始化,而不是以 0 作為缺省值,這是因為 T 不僅僅可能是內(nèi)置類型,也可能是自定義類型,比如 string、list、vector;

當(dāng) T 為自定義類型時,0 就不一定能夠?qū)?val 進(jìn)行初始化,所以我們需要使用 T 的匿名對象來調(diào)用默認(rèn)構(gòu)造完成初始化工作;當(dāng) T 為內(nèi)置類型時,我們?nèi)匀豢梢砸赃@種方式進(jìn)行初始化,因為 內(nèi)置類型也具有構(gòu)造函數(shù),你沒聽錯,內(nèi)置類型也是有構(gòu)造函數(shù)的,大家可以理解為,為了解決上面這種情況,編譯器對內(nèi)置類型進(jìn)行了特殊處理;image-20221130104431455

利用匿名對象調(diào)用默然構(gòu)造函數(shù)來作為缺省值的方法在下面 resize、insert 等接口中也有體現(xiàn)。

2、擴(kuò)容機制

vector 的擴(kuò)容機制和 string 的擴(kuò)容機制是一樣的,因為它們都是動態(tài)增長的數(shù)組:VS 下大概是 1.5 被擴(kuò)容,Linux g++ 下是標(biāo)準(zhǔn)的二倍擴(kuò)容,測試用例如下:

void TestVectorExpand() {size_t sz;
	vectorv;
	sz = v.capacity();
	cout<< "making v grow:\n";
	for (int i = 0; i< 100; ++i) {v.push_back(i);
		if (sz != v.capacity()) {	sz = v.capacity();
			cout<< "capacity changed: "<< sz<< '\n';
		}
	}
}

image-20221130165120492

image-20221130165513728

3、三種遍歷方式

和 string 一樣,vector 也支持三種遍歷方式 – 下標(biāo)加[]遍歷、迭代器遍歷、范圍for遍歷:image-20221130170102726

需要注意的是,vector 和 string 之所以支持 下標(biāo) + [] 的方式遍歷,是因為它們底層都是數(shù)組,而數(shù)組支持隨機訪問,但是像我們后面要學(xué)習(xí)的 list set map 等容器,它們的底層不是數(shù)組,不支持隨機訪問,就只能通過迭代器和范圍 for 的方式進(jìn)行遍歷了;不過,范圍 for 只是一個外殼,它在使用時也是被替換成迭代器,所以其實迭代器遍歷才是最通用的遍歷方式。

4、容量操作

vector 有如下容量相關(guān)的接口:image-20221130171031156

其中,最重要的兩個函數(shù)是 reserve 和 resize,reserve 只用于擴(kuò)容,它不改變 size 的大??;而 resize 是擴(kuò)容加初始化,既會改變 capacity,也會改變 size;image-20221130171946440

注意:reserve 和 resize,包括后面的 clear 函數(shù)都不會縮容,因為縮容需要開辟新空間、拷貝數(shù)據(jù)、釋放舊空間,而對于自定義類型又有可能存在深拷貝問題,時間開銷極大;vector 中唯一可能縮容的函數(shù)就只有 shrink_to_fit,對于它來說,如果 capacity 大于 size,它會進(jìn)行縮容,讓二者相等。image-20221130172054823

5、元素訪問

vector 提供了如下接口來進(jìn)行元素訪問:image-20221130173538875

其中,operator 和 at 都是返回 pos 下標(biāo)位置元素的引用,且它們內(nèi)部都會對 pos 的合法性進(jìn)行檢查;不同的是,operator[] 中如果檢查到 pos 非法,那么它會直接終止程序,報斷言錯誤,而 at 則是拋異常;image-20221130174119352

image-20221130174711329

注:release 模式下檢查不出斷言錯誤。

6、修改 – 迭代器失效

vector 提供了如下接口來進(jìn)行修改操作:image-20221130174817482

assign && push_back && pop_back

assign 函數(shù)用來替換 vector 對象中的數(shù)據(jù),支持 n 個 val 替換,以及迭代器區(qū)間替換,push_back 尾插、pop_back 尾插,這些接口的使用和 string 一模一樣,這里就不再過多闡釋;image-20221130195759960

insert && erase

和 string 不同,為了提高規(guī)范性,STL 中的容器都統(tǒng)一使用 iterator 作為 pos 的類型,并且插入/刪除后會返回 pos:image-20221130202538822

image-20221130202557436

所以,以后我們?nèi)绻谥虚g插入或刪除元素的話,必須配合算法庫里面的 find 函數(shù)來使用:image-20221130202728072

image-20221130203446103

同時,在 VS 下,insert 和 erase 之后會導(dǎo)致 pos 迭代器失效,如果需要再次使用,需要更新 pos,如下:image-20221130203640015

image-20221130203738460

不過,在 Linux 下不會出現(xiàn)這個問題:image-20221130204055497

造成這個問題的根本原因是 VS 使用的 PJ 版本對 iterator 進(jìn)行了封裝,在每次 inset 和 erase 之后對迭代器進(jìn)行了特殊處理,而 g++ 使用的 SGI 版本中的 iterator 是原生指針,具體細(xì)節(jié)在后文 vector 的模擬實現(xiàn)中我們再討論;

但是為了代碼的可移植性,我們 統(tǒng)一認(rèn)為 insert 和 erase 之后迭代器會失效,所以,如果要再次使用迭代器,我們必須對其進(jìn)行更新;我們以移除 vector 中的所有偶數(shù)為例:image-20221130204931492

swap

和 vector 一樣,由于算法庫 swap 函數(shù)存在深拷貝的問題,vector 自己提供了一個不需要深拷貝的 swap 函數(shù),用來交換兩個 vector 對象:image-20221130205429423

同時,為了避免我們不使用成員函數(shù)的 swap,vector 還將算法庫中的 swap 進(jìn)行了重載,然后該重載函數(shù)的內(nèi)部又去調(diào)用成員函數(shù) swap:image-20221130205953712

image-20221130210831942


二、vector 的模擬實現(xiàn) 1、淺析 vector 源碼

對于編程來說,學(xué)習(xí)初期進(jìn)步最快的方式就是閱讀別人優(yōu)秀的代碼,理解其中的邏輯和細(xì)節(jié)后自己獨立的去實現(xiàn)幾次,學(xué)習(xí) STL 也是如此;我們可以適當(dāng)?shù)娜ラ喿x STL 的源碼,當(dāng)然我們并不是要逐行的進(jìn)行閱讀,因為這樣太耗費時間,況且其中很多 C++ 的語法我們也還沒學(xué)。

當(dāng)前階段,我們閱讀 STL 源碼是為了學(xué)習(xí) STL 庫的核心框架,然后根據(jù)這個框架自己模擬實現(xiàn)一個簡易的 vector (只實現(xiàn)核心接口);閱讀源碼與模擬實現(xiàn)能夠讓我們更好的了解底層,對 STL 做到 能用,并且 明理。

我們在 【STL簡介 – string 的使用及其模擬實現(xiàn)】 中對 STL 做了一些基本的介紹,知道了 STL 由原始版本主要發(fā)展出了 PJ、RW 和 SGI 版本,其中,微軟的 VS 系列使用的就是 PJ 版,但是由于其命名風(fēng)格的原因,我們閱讀源碼時一般選擇 SGI 版,而且 Linux 下 gcc/g++ 也是使用的 SGI 版本,再加上侯捷老師有一本非常著名的書 《STL源碼剖析》也是使用的 SGI 版本,所以以后閱讀和模擬實現(xiàn) STL 時我都使用這個版本。

《STL源碼剖析》電子版和 《stl30》源碼我都放在下面了,需要的可以自?。?/p>

STL源碼剖析:https://www.aliyundrive.com/s/Nc4mpLC43kj
stl30:https://www.aliyundrive.com/s/pnwMuB9uwEN

vector 的部分源碼如下:

//vector.h
#ifndef __SGI_STL_VECTOR_H
#define __SGI_STL_VECTOR_H

#include 
#include 
#include#ifdef __STL_USE_NAMESPACES
using __STD::vector;
//stl_vector.h
templateclass vector {public:
  typedef T value_type;
  typedef value_type* pointer;
  typedef const value_type* const_pointer;
  typedef value_type* iterator;
  typedef const value_type* const_iterator;
  typedef value_type& reference;
  typedef const value_type& const_reference;
  typedef size_t size_type;
  typedef ptrdiff_t difference_type;
    
   //成員函數(shù)
    
protected:
  typedef simple_allocdata_allocator;
  iterator start;
  iterator finish;
  iterator end_of_storage;
}

可以看到,vector.h 僅僅是將幾個頭文件包含在一起,vector 的主要實現(xiàn)都在 stl_vector.h 里面。

2、核心框架

我們可以根據(jù)上面的 vector 源碼來得出 vector 的核心框架:

namespace thj {templateclass vector {public:
        typedef T* iterator;
        typedef const T* const_iterator;

    public:
        //成員函數(shù)

    private:
        T* _start;
        T* _finish;
        T* _end_of_storage;
    };
}

可以看到,vector 的底層和 string 一樣,都是一個指針指向一塊動態(tài)開辟的數(shù)組,但是二者不同的是,string 是用 _size 和 _capacity 兩個 size_t 的成員函數(shù)來維護(hù)這塊空間,而 vector 是用 _finish 和 _end_of_storage 兩個指針來維護(hù)這塊空間;雖然 vector 使用指針看起來難了一些,但本質(zhì)上其實是一樣的 – _size = _finish - _start, _capacity = _end_of_storage - _start;image-20221130093303775

3、構(gòu)造函數(shù)錯誤調(diào)用問題

在我們模擬實現(xiàn)了構(gòu)造函數(shù)中的迭代器區(qū)間構(gòu)造和 n 個 val 構(gòu)造后,我們會發(fā)現(xiàn)一個奇怪的問題,我們使用 n 個 val 來構(gòu)造其他類型的對象都沒問題,唯獨構(gòu)造 int 類型的對象時會編譯出錯,如下:

//迭代器區(qū)間構(gòu)造
templatevector(InputIterator first, InputIterator last)
    :_start(nullptr)
        , _finish(nullptr)
        , _end_of_storage(nullptr)
    {while (first != last)
        {push_back(*first);
            ++first;
        }
    }

//n個val構(gòu)造
vector(size_t n, const T& val = T())
    :_start(nullptr)
        , _finish(nullptr)
        , _end_of_storage(nullptr)
    {reserve(n);
        for (size_t i = 0; i< n; i++)
            push_back(val);
    }

image-20221130223227953

這是由于編譯器在進(jìn)行模板實例化以及函數(shù)參數(shù)匹配時會調(diào)用最匹配的一個函數(shù),當(dāng)我們將 T 實例化為 int 之后,由于兩個參數(shù)都是 int,所以對于迭代器構(gòu)造函數(shù)來說,它會直接將 InputIterator 實例化為 int;

但對于 n 個 val 的構(gòu)造來說,它不僅需要將 T 實例化為 int,還需要將第一個參數(shù)隱式轉(zhuǎn)換為 size_t;所以編譯器默認(rèn)會調(diào)用迭代器構(gòu)造,同時由于迭代器構(gòu)造內(nèi)部會對 first 進(jìn)行解引用,所以這里報錯 “非法的間接尋址”;

解決方法有很多種,比如將第一個參數(shù)強轉(zhuǎn)為 int,又或者是將 n 個 val 構(gòu)造的第一個參數(shù)定義為 int,我們這里和 STL 源碼保持一致 – 提供第一個參數(shù)為 int 的 n 個 val 構(gòu)造的重載函數(shù):image-20221130224838261

//n個val構(gòu)造
vector(size_t n, const T& val = T())
    :_start(nullptr)
        , _finish(nullptr)
        , _end_of_storage(nullptr)
    {reserve(n);
        for (size_t i = 0; i< n; i++)
            push_back(val);
    }

//n個val構(gòu)造 -- 重載
vector(int n, const T& val = T())
    :_start(nullptr)
        , _finish(nullptr)
        , _end_of_storage(nullptr)
    {reserve(n);
        for (int i = 0; i< n; i++)
            push_back(val);
    }
4、insert 和 erase 迭代器失效問題

我們模擬實現(xiàn)的 insert 和 erase 函數(shù)如下:

//任意位置插入
iterator insert(iterator pos, const T& x)
{assert(pos >= _start);
    assert(pos<= _finish);

    //擴(kuò)容導(dǎo)致 pos 迭代器失效
    if (size() == capacity())
    {size_t oldPos = pos - _start;  //記錄pos,避免擴(kuò)容后pos變?yōu)橐爸羔?        size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
        reserve(newCapacity);
        pos = _start + oldPos;  //擴(kuò)容之后更新pos
    }

    iterator end = _finish - 1;
    while (end >= pos)
    {*(end + 1) = *end;
        --end;
    }

    *pos = x;
    ++_finish;
    return pos;
}

//任意位置刪除 -- erase 之后也認(rèn)為 pos 迭代器失效
iterator erase(iterator pos)
{assert(pos >= _start);
    assert(pos< _finish);

    iterator begin = pos;
    while (begin< _finish - 1)
    {*begin = *(begin + 1);
        ++begin;
    }
    --_finish;
    return pos;
}

我們在 vector 的使用中就提到 VS 下 insert 和 erase 后迭代器會失效,再次訪問編譯器會直接報錯,這是因為 PJ 版本下 iterator 不是原生指針,如下:image-20221130225551770

image-20221130225619075

可以看到,VS 中的迭代器是一個類,當(dāng)我們進(jìn)行 insert 或者 erase 操作之后,iterator 中的某個函數(shù)可能會將 pos 置為空或者其他操作,導(dǎo)致再次訪問 pos 報錯,除非我們每次使用后都更新 pos:image-20221130230528665

image-20221130230625835

而 Linux 下的 g++ 卻不會出現(xiàn)這樣的問題,因為 g++ 使用的是 SGI 版本,該版本的源碼我們在上面也已經(jīng)見過了,其迭代器是一個原生指針,同時它內(nèi)部 insert 和 erase 接口的實現(xiàn)也和我們模擬的類似,可以看到,我們并沒有在函數(shù)內(nèi)部改變 pos (改變也沒用,因為這是形參),所以 insert、erase 之后 pos 可以繼續(xù)使用;image-20221130231000841

image-20221130231437769

但是這里也存在一個問題,insert 和 erase 之后 pos 的意義變了 – 我們插入元素后 pos 不再指向原來的元素,而是指向我們新插入的元素;同樣,erase 之后 pos 也不再指向原來的元素,而是指向該元素的后一個元素;特別是當(dāng) erase 尾部的數(shù)據(jù)后,pos 就等于 _finish 了;

那么對于不了解底層的人就極易寫出下面這樣的代碼 – 刪除 vector 中的所有偶數(shù):image-20221130233018001

image-20221130233101684

可以看到,第一個由于刪除元素后 pos 不再指向原位置,而是指向下一個位置,所以 erase 之后會導(dǎo)致一個元素被跳過,導(dǎo)致部分偶數(shù)沒有被刪除,但好在末尾是奇數(shù),所以程序能夠正常運行;

但是第二個就沒那么好運了,由于最后一個元素是偶數(shù),所以 erase 之后 pos 直接指向了 _finish 的下一個位置,循環(huán)終止條件失效,發(fā)生越界。

綜上,為了保證程序的跨平臺性,我們統(tǒng)一認(rèn)為 insert 和 erase 之后迭代器失效,必須更新后才能再次使用。

5、reserve 函數(shù)的淺拷貝問題

除了上面這兩個問題之外,我們的 vector 還存在一個問題 – reserve 函數(shù) 深層次的淺拷貝問題,模擬實現(xiàn)的 reserve 函數(shù)如下:

void reserve(size_t n)
{if (n >capacity())  //reserve 函數(shù)不縮容
    {T* tmp = new T[n];
        memcpy(tmp, _start, sizeof(T) * size());
        size_t oldSize = _finish - _start;  //記錄原來的size,避免擴(kuò)容不能確定_finish
        delete[] _start;

        _start = tmp;
        _finish = _start + oldSize;
        _end_of_storage = _start + n;
    }
}

很多同學(xué)看到這段代碼的時候可能會認(rèn)為它沒問題,的確,對于內(nèi)置類型來說它確實是進(jìn)行了深拷貝,但是對于需要進(jìn)行深拷貝的自定義類型來說它就有問題了,如下:image-20221201000643954

image-20221201002804642

程序報錯的原因如圖:當(dāng) v 中的元素達(dá)到4個再進(jìn)行插入時,push_back 內(nèi)部就會調(diào)用 reserve 函數(shù)進(jìn)行擴(kuò)容,而擴(kuò)容時我們雖然對存放 v1 v2 的空間進(jìn)行了深拷貝,但是空間里面的內(nèi)容我們是使用 memcpy 按字節(jié)拷貝過來的,這就導(dǎo)致原來的 v 里面的 string 元素和現(xiàn)在 v 里面的元素指向的是同一塊空間。

當(dāng)我們拷貝完畢之后使用 delete[] 釋放原空間,而 delete[] 釋放空間時對于自定義類型會調(diào)用其析構(gòu)函數(shù),而 v 內(nèi)部的 string 對象又會去調(diào)用自己的析構(gòu)函數(shù),所以 delete[] 完畢后原來的 v 以及 v 中各個元素指向的空間都被釋放了,此時現(xiàn)在的 v 里面的每個元素全部指向已經(jīng)釋放的空間。

從第一張圖中我們也可以看到,最后一次 push_back 之后 v 里面的元素全部變紅了;最終,當(dāng)程序結(jié)束自動調(diào)用析構(gòu)函數(shù)時,就會去析構(gòu)剛才已經(jīng)被釋放掉的 v 中的各個 string 對象指向的空間,導(dǎo)致同一塊空間被析構(gòu)兩次,程序出錯。

所以,在 reserve 內(nèi)部,我們不能使用 memcpy 直接按字節(jié)拷貝原空間中的各個元素,因為這些元素可能也指向一塊動態(tài)開辟的空間,而應(yīng)該調(diào)用每個元素的拷貝構(gòu)造進(jìn)行拷貝,如圖:image-20221201004838430

具體代碼實現(xiàn)如下:

//擴(kuò)容
void reserve(size_t n)
{if (n >capacity())  //reserve 函數(shù)不縮容
    {T* tmp = new T[n];
        //memcpy(tmp, _start, sizeof(T) * size());  //error

        //memcpy有自定義類型的淺拷貝問題,需要對每個元素使用拷貝構(gòu)造進(jìn)行深拷貝
        for (int i = 0; i< size(); i++)
            tmp[i] = _start[i];  //拷貝構(gòu)造

        size_t oldSize = _finish - _start;  //記錄原來的size,避免擴(kuò)容不能確定_finish
        delete[] _start;

        _start = tmp;
        _finish = _start + oldSize;
        _end_of_storage = _start + n;
    }

image-20221201005431302

注意:有的同學(xué)看到這里使用的是賦值運算符就認(rèn)為這里調(diào)用的賦值重載,其實不是的,因為這里完成的是初始化工作,編譯器會自動轉(zhuǎn)換為調(diào)用拷貝構(gòu)造函數(shù)。

6、模擬 vector 整體代碼

在了解了 vector 的核心框架以及解決了上面這幾個疑難點之后,剩下的東西就變得很簡單了,所以我這里直接給出結(jié)果,大家可以根據(jù)自己實現(xiàn)的對照一下,如有錯誤,也歡迎大家指正:

//vector.h
#pragma once
#include#include 
#include#include 

namespace thj {//防止命名沖突
	templateclass vector {public:
		typedef T* iterator;
		typedef const T* const_iterator;

	public:
		//-------------------------------------constructor---------------------------------------//
		//無參構(gòu)造
		vector()
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{}

		//迭代器區(qū)間構(gòu)造
		templatevector(InputIterator first, InputIterator last)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{	while (first != last)
			{		push_back(*first);
				++first;
			}
		}

		//n個val構(gòu)造
		vector(size_t n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{	reserve(n);
			for (size_t i = 0; i< n; i++)
				push_back(val);
		}

		//n個val構(gòu)造 -- 重載
		vector(int n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{	reserve(n);
			for (int i = 0; i< n; i++)
				push_back(val);
		}

		//拷貝構(gòu)造 -- 寫法1
		//vector(const vector& v)
		//{//	T* tmp = new T[v.capacity()];
		//	memcpy(tmp, v._start, sizeof(T) * v.capacity());
		//	_start = tmp;
		//	_finish = _start + v.size();
		//	_end_of_storage = _start + v.capacity();
		//}

		//拷貝構(gòu)造 -- 寫法2
		//vector(const vector& v)
		//	: _start(nullptr)
		//	, _finish(nullptr)
		//	, _end_of_storage(nullptr)
		//{//	reserve(v.capacity());
		//	for (size_t i = 0; i< v.size(); i++)
		//		push_back(v[i]);
		//}

		//拷貝構(gòu)造 -- 現(xiàn)代寫法
		vector(const vector& v)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{	vectortmp(v.begin(), v.end());  //復(fù)用構(gòu)造函數(shù)和swap函數(shù)
			swap(tmp);
		}

		//析構(gòu)函數(shù)
		~vector() {	delete[] _start;
			_start = _finish = _end_of_storage = nullptr;
		}

		//賦值重載
		vector& operator=(vectorv)  //復(fù)用拷貝構(gòu)造,存在自我賦值的問題,但不影響程序正確性
		{	swap(v);
			return *this;
		}

		//----------------------------------iterator---------------------------------------//
		iterator begin()
		{	return _start;
		}

		iterator end()
		{	return _finish;
		}

		const_iterator begin() const
		{	return _start;
		}

		const_iterator end() const
		{	return _finish;
		}

		//-------------------------------------capacity----------------------------------------//
		size_t size() const
		{	return _finish - _start;
		}

		size_t capacity() const
		{	return _end_of_storage - _start;
		}

		bool empty() const
		{	return _start == _finish;
		}

		//擴(kuò)容
		void reserve(size_t n)
		{	if (n >capacity())  //reserve 函數(shù)不縮容
			{		T* tmp = new T[n];
				//memcpy(tmp, _start, sizeof(T) * size());  //error

				//memcpy有自定義類型的淺拷貝問題,需要對每個元素使用拷貝構(gòu)造進(jìn)行深拷貝
				for (int i = 0; i< size(); i++)
					tmp[i] = _start[i];  //拷貝構(gòu)造

				size_t oldSize = _finish - _start;  //記錄原來的size,避免擴(kuò)容不能確定_finish
				delete[] _start;

				_start = tmp;
				_finish = _start + oldSize;
				_end_of_storage = _start + n;
			}
		}

		//擴(kuò)容并初始化
		void resize(size_t n, T x = T())
		{	if (n >capacity())  //resize 不縮容
			{		reserve(n);
			}
			if (n >size())
			{		while (_finish< _start + n)
				{*_finish = x;
					++_finish;
				}
			}
			if (n< size())
			{		_finish = _start + n;
			}
		}
        
		//----------------------------------------element access---------------------------------//
		T& operator[](size_t pos)
		{	assert(pos< size());  //檢查越界
			return _start[pos];
		}

		const T& operator[](size_t pos) const
		{	assert(pos< size());
			return _start[pos];
		}

		//----------------------------------------modifys-----------------------------------------//
		//尾插
		void push_back(const T& n)
		{	if (size() == capacity())
			{		size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newCapacity);
			}
			*_finish = n;
			++_finish;
		}

		//尾刪
		void pop_back()
		{	assert(!empty());
			--_finish;
		}

		//任意位置插入 -- 插入后認(rèn)為迭代器失效
		iterator insert(iterator pos, const T& x)
		{	assert(pos >= _start);
			assert(pos<= _finish);

            //擴(kuò)容會導(dǎo)致迭代器失效
			if (size() == capacity())
			{		size_t oldPos = pos - _start;  //記錄pos,避免擴(kuò)容后pos變?yōu)橐爸羔?				size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newCapacity);
				pos = _start + oldPos;  //擴(kuò)容之后更新pos
			}

			iterator end = _finish - 1;
			while (end >= pos)
			{		*(end + 1) = *end;
				--end;
			}

			*pos = x;
			++_finish;
			return pos;
		}

		//任意位置刪除 -- erase 之后也認(rèn)為 pos 迭代器失效
		iterator erase(iterator pos)
		{	assert(pos >= _start);
			assert(pos< _finish);

			iterator begin = pos;
			while (begin< _finish - 1)
			{		*begin = *(begin + 1);
				++begin;
			}
			--_finish;
			return pos;
		}

		//交換兩個對象
		void swap(vector& v)
		{	std::swap(_start, v._start);  //復(fù)用算法庫的swap函數(shù)
			std::swap(_finish, v._finish);
			std::swap(_end_of_storage, v._end_of_storage);
		}

		void clear()
		{	_finish = _start;
		}

	private:
		T* _start;
		T* _finish;
		T* _end_of_storage;
	};
}

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

分享標(biāo)題:【C++】vector的使用及其模擬實現(xiàn)-創(chuàng)新互聯(lián)
URL地址:http://jinyejixie.com/article6/dshiog.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供虛擬主機、網(wǎng)站排名靜態(tài)網(wǎng)站、品牌網(wǎng)站制作自適應(yīng)網(wǎng)站、網(wǎng)站設(shè)計

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都app開發(fā)公司
庐江县| 文昌市| 济源市| 卢湾区| 常山县| 云梦县| 泰州市| 鞍山市| 湖北省| 盐城市| 阿克陶县| 潜山县| 丰镇市| 柯坪县| 涟源市| 四平市| 新田县| 洛川县| 平江县| 高阳县| 齐河县| 南木林县| 吉水县| 蓝山县| 三穗县| 高淳县| 马关县| 平利县| 葵青区| 静宁县| 泾阳县| 镇远县| 武隆县| 龙州县| 沈丘县| 胶州市| 余江县| 定兴县| 康乐县| 龙山县| 泗洪县|