??主要講述vector的模擬實(shí)現(xiàn)。
創(chuàng)新互聯(lián)專注于木蘭網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供木蘭營(yíng)銷型網(wǎng)站建設(shè),木蘭網(wǎng)站制作、木蘭網(wǎng)頁(yè)設(shè)計(jì)、木蘭網(wǎng)站官網(wǎng)定制、微信小程序服務(wù),打造木蘭網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供木蘭網(wǎng)站排名全網(wǎng)營(yíng)銷落地服務(wù)。文章目錄??同string類模擬實(shí)現(xiàn)一致,此處為了解決命名沖突問(wèn)題,我們使用添加命名空間myvector
的方式來(lái)處理。
#pragma once
namespace myvector
{templateclass vector
{typedef T* iterator;//將模板T*命名為迭代器iterator
public:
private:
iterator _start;//起始
iterator _finish;//結(jié)束
iterator _end_of_storage;//容量空間
};
}
??由于后續(xù)涉及到迭代器問(wèn)題,若將typedef T* iterator;
定義成私有,則無(wú)法在類外很好的使用。此處修改如下:
#pragma once
namespace myvector
{templateclass vector
{ public:
typedef T* iterator;//將模板T*命名為迭代器iterator
typedef const T* const_iterator;
private:
iterator _start;//起始
iterator _finish;//結(jié)束
iterator _end_of_storage;//容量空間
};
}
??
??
??1)、構(gòu)造函數(shù)
??對(duì)構(gòu)造函數(shù),我們之前學(xué)習(xí)時(shí)看到其中有內(nèi)存池的相關(guān)內(nèi)容,此處由于我們暫時(shí)沒(méi)學(xué)習(xí)它,故對(duì)vector的模擬實(shí)現(xiàn)中我們不使用它。
vector() //構(gòu)造函數(shù)
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{}
??
??2)、析構(gòu)函數(shù)
~vector()//析構(gòu)函數(shù)
{ delete[] _start;//null出來(lái)的空間是連續(xù)一塊的,以_start為起始點(diǎn)。注意delete的使用方式
_start = _finish = _end_of_storage = nullptr;
}
??
??
??1)、庫(kù)函數(shù)中聲明回顧
??2)、push_back模擬實(shí)現(xiàn)
void push_back(const T& x)
{ //涉及擴(kuò)容檢查
if (_finish == _end_of_storage)
{ reserve(capacity() == 0?4:capacity() * 2);
}
//尾插數(shù)據(jù)
*_finish = x;
_finish++;
}
??為什么需要使用引用和const修飾?
??因?yàn)檫@里使用的是T模板參數(shù),我們傳入的值可能是內(nèi)置類型,也可能是自定義類型,如果是后者,則傳值傳參代價(jià)很大。
??
??3)、pop_back模擬實(shí)現(xiàn)
void pop_back()
{ assert(_finish >_start);
_finish--;
}
??
??
??
??
??1)、庫(kù)函數(shù)中聲明回顧
??2)、模擬實(shí)現(xiàn)
size_t size()const
{ return _finish - _start;
}
size_t capacity()const
{ return _end_of_storage - _start;
}
void reserve(size_t n)
{ if (n >capacity())//滿足該條件才進(jìn)行擴(kuò)容
{ size_t sz = size();//因?yàn)楹罄m(xù)重新確定指向關(guān)系時(shí)需要知道size值
T* tmp = new T[n];
if (_start)//說(shuō)明原先空間有數(shù)據(jù),
{memcpy(tmp, _start, sizeof(T) * sz);//需要挪動(dòng)
delete[] _start;//釋放舊空間
}
//重新確定指向關(guān)系
_start = tmp;
_finish = _start + sz;
//_finish = _start + size();//如果是在這里獲取size值,則在原先空間有數(shù)據(jù)的情況下,_start已經(jīng)被delete
_end_of_storage = _start + n;
}
}
??
??
??
??1)、庫(kù)函數(shù)中聲明回顧
??2)、模擬實(shí)現(xiàn)
T& operator[](size_t pos)//加&是為了支持可讀可寫(xiě)
{ assert(pos< size());//檢查下標(biāo)是否非法
return _start[pos];
}
const T& operator[](size_t pos)const
{ assert(pos< size());
return _start[pos];
}
??
??
??1)、普通迭代器
//vector的迭代器就是原生指針
iterator begin()
{ return _start;
}
iterator end()
{ return _finish;
}
??
??
??2)、const修飾的迭代器
??為什么需要?
??存在如下的情況:const vector
,所創(chuàng)建的vector對(duì)象被const修飾,如果直接使用vector
,則屬于權(quán)限放大。
typedef const T* const_iterator;
const const_iterator begin()const
{ return _start;
}
const const_iterator end()const
{ return _finish;
}
void Func(const vector& v)
{vector::const_iterator it = v.begin();
while (it != v.end())
{ //*it = 10;//error
cout<< *it<< " ";
++it;
}
cout<< endl;
for (auto e : v)//此處若使用范圍for,const對(duì)象會(huì)調(diào)用對(duì)應(yīng)的const迭代器
{ cout<< e<< " ";
}
cout<< endl;
}
??
??3)、為什么說(shuō)范圍for是傻瓜式替換?
??只要我們仿照庫(kù)中使用對(duì)應(yīng)字符begin、end,則訪問(wèn)for就能起效。相應(yīng)的,如果我們使用了Begin、End等其它字母,則在我們模擬的vector中范圍for失效。
??
??
??1)、庫(kù)函數(shù)中聲明回顧
??2)、insert模擬實(shí)現(xiàn)1.0
void insert(iterator pos, const T& val)
{ assert(pos<= _finish && pos >= _start);
//擴(kuò)容檢查
if (_finish == _end_of_storage)
{ reserve(capacity() == 0 ? 4 : capacity() * 2);
}
//數(shù)據(jù)挪動(dòng)
iterator end = _finish - 1;
while (end >= pos)
{ *(end + 1) = *end;
end--;
}
//插入val值
*pos = val;
++_finish;
}
??
??
??3)、insert涉及擴(kuò)容時(shí)迭代器失效問(wèn)題
??問(wèn)題:
??
??原因解釋:
??
??
??4)、insert模擬實(shí)現(xiàn)2.0
??解決方案: 若擴(kuò)容,則要順帶更新pos指向位置
//保存二者指針差距
size_t len = pos - _start;
//擴(kuò)容后更新pos指向
pos = len + _start;
void insert(iterator pos, const T& val)
{ assert(pos<= _finish && pos >= _start);
//擴(kuò)容檢查
if (_finish == _end_of_storage)
{ //保存二者指針差距
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : capacity() * 2);
//擴(kuò)容后更新pos指向
pos = len + _start;
}
//數(shù)據(jù)挪動(dòng)
iterator end = _finish - 1;
while (end >= pos)
{ *(end + 1) = *end;
end--;
}
//插入val值
*pos = val;
++_finish;
}
??
??
??
??1)、問(wèn)題引入與現(xiàn)象分析
??接上一階段代碼,分析下述情形:
??一開(kāi)始我們使用find找到了p位置,然后在p位置前插入一次,現(xiàn)在我們變?yōu)閜位置前連續(xù)插入多次。問(wèn):是否能成功?
//使用算法中的find
auto p = find(v.begin(), v.end(), 3);
if (p != v.end())//找到了
{ v.insert(p, 30);//1、插入一個(gè)30
cout<< *p<< endl;//2、再次來(lái)到p的位置
v.insert(p, 40);//3、我們p位置前插入一個(gè)40,問(wèn):是否能成功?
}
??現(xiàn)象如下:
??
??可能出現(xiàn)疑問(wèn)如下:我們?cè)?.5.1中解決了insert中pos位置更新的問(wèn)題,為什么此處p仍舊不起效?
??這里我們需要思考上述寫(xiě)的insert函數(shù)中,形參pos和實(shí)參p之間的關(guān)系??芍獣缘氖?,在insert函數(shù)中,它們是值傳遞,故形參改變不影響實(shí)參。
void insert(iterator pos, const T& val)
{ assert(pos<= _finish && pos >= _start);
//擴(kuò)容檢查
if (_finish == _end_of_storage)
{ //保存二者指針差距
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : capacity() * 2);
//擴(kuò)容后更新pos指向
pos = len + _start;
}
//數(shù)據(jù)挪動(dòng)
iterator end = _finish - 1;
while (end >= pos)
{ *(end + 1) = *end;
end--;
}
//插入val值
*pos = val;
++_finish;
}
??
??
??2)、解決方案
??①一個(gè)相對(duì)比較適合的方法是,在此類情況中,最好別再p位置失效后再去訪問(wèn)p。
??
??
??②有人可能提出,我們?cè)趇nsert中為pos加上一個(gè)引用,即傳引用返回,這樣不就解決了?void insert(iterator& pos, const T& val)
void insert(iterator& pos, const T& val)
{ assert(pos<= _finish && pos >= _start);
//擴(kuò)容檢查
if (_finish == _end_of_storage)
{ //保存二者指針差距
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : capacity() * 2);
//擴(kuò)容后更新pos指向
pos = len + _start;
}
//數(shù)據(jù)挪動(dòng)
iterator end = _finish - 1;
while (end >= pos)
{ *(end + 1) = *end;
end--;
}
//插入val值
*pos = val;
++_finish;
}
??事實(shí)上這樣做,針對(duì)insert而言確實(shí)可以解決問(wèn)題,但同樣會(huì)面臨新的問(wèn)題。
??第一,這樣的模擬實(shí)現(xiàn)與庫(kù)中不匹配,庫(kù)中直接使用iterator pos
;
??第二,這樣做會(huì)帶來(lái)新的問(wèn)題,如下:
v.insert(v.begin(), 1);
??此段代碼無(wú)法編譯通過(guò)。因?yàn)閎egin模擬實(shí)現(xiàn)時(shí),我們使用的是iterator傳值返回,中間會(huì)生成一份臨時(shí)變量,具有常性,后續(xù)insert處權(quán)限放大。
????Ⅰ、若為insert加上const,那么又無(wú)法解決修改問(wèn)題。
????Ⅱ、而如果將begin也寫(xiě)為傳引用返回,iterator& begin()
,這樣會(huì)使得begin具有修改能力,反而增添麻煩。
iterator begin()
{ return _start;
}
??
??
??3)、思考:上述值傳遞中,p一定存在迭代器失效問(wèn)題嗎?
??回答:同3.5.2中所講,在涉及擴(kuò)容問(wèn)題時(shí),p才存在失效。
??演示:如下述,假如我們一開(kāi)始插入5個(gè)數(shù)值,容量空間足夠的情況下,此處不存在p失效問(wèn)題。
??
??
??4)、insert為push_back提供復(fù)用
void push_back(const T& x)
{ insert(end(), x);
}
??
??
??5)、insert模擬實(shí)現(xiàn)3.0:案例演示
??案例要求: 在所有的偶數(shù)前插入該偶數(shù)的二倍值。
??代碼演示+現(xiàn)象分析:
??我們以上述insert2.0版本為例進(jìn)行演示,順帶再來(lái)回顧一下迭代器失效問(wèn)題。
void test_vector5()
{std::vectorv;
v.reserve(10);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
//v.push_back(5);
//在所有偶數(shù)前插入該偶數(shù)的2倍
auto it = v.begin();
while (it != v.end())
{ if (*it % 2 == 0)
{ v.insert(it, *it * 2);
}
++it;
}
}
??上述代碼我們直接運(yùn)行則程序崩潰無(wú)輸出結(jié)果,調(diào)試后發(fā)現(xiàn)如下:it始終指向2的位置。這就是迭代器失效的另一種模式:因?yàn)閿?shù)據(jù)挪動(dòng),導(dǎo)致外部指針指向錯(cuò)亂。
??ps: 迭代器失效的第一種模式:函數(shù)內(nèi)擴(kuò)容,導(dǎo)致野指針。
??
??為了解決上述問(wèn)題,也一并解決insert中擴(kuò)容后外部迭代器失效問(wèn)題,一個(gè)方案如下:
????Ⅰ、對(duì)insert
函數(shù),模仿庫(kù)中帶上iterator
返回值;
????Ⅱ、對(duì)原先的二倍插入循環(huán),需要更新it
指向的新位置,旨在解決擴(kuò)容后外部迭代器失效問(wèn)題。
iterator insert(iterator pos, const T& val)
{ assert(pos<= _finish && pos >= _start);
//擴(kuò)容檢查
if (_finish == _end_of_storage)
{ //保存二者指針差距
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : capacity() * 2);
//擴(kuò)容后更新pos指向
pos = len + _start;
}
//數(shù)據(jù)挪動(dòng)
iterator end = _finish - 1;
while (end >= pos)
{ *(end + 1) = *end;
end--;
}
//插入val值
*pos = val;
++_finish;
return pos;
}
void test_vector5()
{std::vectorv;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
//v.push_back(5);
//在所有偶數(shù)前插入該偶數(shù)的2倍
auto it = v.begin();
while (it != v.end())
{ if (*it % 2 == 0)
{ it=v.insert(it, *it * 2);
++it;
}
++it;
}
for (auto e : v)
{ cout<< e<< " ";
}
cout<< endl;
}
??演示結(jié)果:
??
??
??
??1)、erase模擬實(shí)現(xiàn)1.0
void erase(iterator pos)
{ assert(pos< _finish && pos >= _start);
iterator end = pos + 1;
while (end< _finish)
{ *(end - 1) = *end;
++end;
}
--_finish;
}
??
??2)、erase是否會(huì)導(dǎo)致迭代器失效?
??①主要看編譯器如何實(shí)現(xiàn)erase函數(shù),不排除有些編譯器以時(shí)間換空間進(jìn)行縮容:
??
if (size()< capacity()/2)
{ // 縮容 -- 以時(shí)間換空間
}
??
??
??②其它案例演示:刪除vector中的偶數(shù)
??使用代碼如下:
void erase(iterator pos)
{ assert(pos< _finish && pos >= _start);
iterator end = pos + 1;
while (end< _finish)
{ *(end - 1) = *end;
++end;
}
--_finish;
}
void test_vector4()
{vectorv;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
//v.push_back(5);
for (auto e : v)
{ cout<< e<< " ";
}
cout<< endl;
//刪除所有偶數(shù)
auto it = v.begin();
while (it != v.end())
{ if(*it % 2 == 0)
{ v.erase(it);
}
++it;
}
for (auto e : v)
{ cout<< e<< " ";
}
cout<< endl;
}
??現(xiàn)象如下:
??
??
??
??
??3)、erase模擬實(shí)現(xiàn)2.0
iterator erase(iterator pos)
{ assert(pos< _finish && pos >= _start);
iterator end = pos + 1;
while (end< _finish)
{ *(end - 1) = *end;
++end;
}
--_finish;
//if (size()< capacity()/2)
//{ // // 縮容 -- 以時(shí)間換空間
//}
return pos;
}
??基于2.0版
本的erase
我們?cè)賮?lái)修改上述 2) 中的題目:
void test_vector4()
{vectorv;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
//v.push_back(5);
for (auto e : v)
{ cout<< e<< " ";
}
cout<< endl;
//刪除所有偶數(shù)
auto it = v.begin();
while (it != v.end())
{ if(*it % 2 == 0)
{ it=v.erase(it);
}
else { ++it;
}
}
for (auto e : v)
{ cout<< e<< " ";
}
cout<< endl;
}
??
??
??
??需要注意的是,上述我們對(duì)迭代器失效的問(wèn)題演示,其結(jié)果是未定義的,因?yàn)獒槍?duì)不同平臺(tái)其STL底層實(shí)現(xiàn)并不一致。
??即,STL只是一個(gè)規(guī)范,其細(xì)節(jié)如何實(shí)現(xiàn)不做要求。
??VS:PJ版。
??g++:SGI版。
??
??
??
3.6、vector::resize??1)、庫(kù)函數(shù)中聲明回顧
??
??2)、模擬實(shí)現(xiàn)
??根據(jù)上述可知,resize
面臨三種情況:
????Ⅰ、當(dāng)n>capacity
:擴(kuò)容+使用val初始化;
????Ⅱ、當(dāng)size
????Ⅲ、當(dāng)n
??
??模擬實(shí)現(xiàn)如下:
void resize(size_t n, const T& val=T())
{ if (n >capacity())
{ reserve(n);
}
if (n >size())//兩種情況:n>capacity、size //只需要初始化即可
while (_finish< _start + n)
{push_back(val);
++_finish;
}
}
else
{ _finish = _start + n;
}
}
??演示驗(yàn)證一:
void test_vector11()
{//resize常用場(chǎng)景:在生成對(duì)象后開(kāi)辟空間
vectorv;
v.resize(5);//驗(yàn)證默認(rèn)缺省值
for (auto e : v)
{ cout<< e<< " ";
}
cout<< endl;
v.resize(10, 2);
for (auto e : v)
{ cout<< e<< " ";
}
cout<< endl;
}
??
??演示驗(yàn)證二:
void test_vector11()
{vectorv1;
v1.reserve(10);
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
v1.resize(8,8);//由大到小,而值只有5個(gè),會(huì)添3個(gè)值
for (auto e : v1)
{ cout<< e<< " ";
}
cout<< endl;
}
??
??
??
??
??1)、庫(kù)函數(shù)中聲明回顧
??
??2)、模擬實(shí)現(xiàn)
T& front()
{ assert(size() >0);
return *_start;
}
T& back()
{ assert(size() >0);
return *(_finish - 1);
}
??
??
??
??
??1)、知識(shí)回顧
??在類和對(duì)象章節(jié),我們?cè)f(shuō)明:拷貝構(gòu)造對(duì)于內(nèi)置類型完成淺拷貝/值拷貝,對(duì)于自定義類型則會(huì)調(diào)用它對(duì)應(yīng)的拷貝構(gòu)造。
??
??
??2)、vector拷貝構(gòu)造分析
??vector的成員變量是內(nèi)置類型,故編譯器默認(rèn)生成的拷貝構(gòu)造函數(shù)完成的是淺拷貝。
??PS:typedef T* iterator;
、此處盡管iterator
是類模板,且T*
會(huì)存在自定義類型的指針,但其仍舊是內(nèi)置類型。
private:
iterator _start;//起始
iterator _finish;//結(jié)束
iterator _end_of_storage;//容量空間
??以如下代碼進(jìn)行拷貝構(gòu)造:
vectorv;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
vectorv2(v);
for (auto e : v2)
{ cout<< e<< " ";
}
cout<< endl;
??淺拷貝帶來(lái)的兩個(gè)問(wèn)題:
????Ⅰ、析構(gòu)兩次
????Ⅱ、一個(gè)對(duì)象的修改,會(huì)影響另一個(gè)對(duì)象
??
??
??
??
vector(const vector& v)
{ _start = new T[v.size()];//此處也可以開(kāi)辟v.capacity()大小的空間,各有各的優(yōu)缺點(diǎn)
memcpy(_start, v._start, sizeof(T)*v.size());//照搬數(shù)據(jù)
_finish = _start + v.size();
_end_of_storage = _start + v.size();//此處this._finish的大小根據(jù)上述我們開(kāi)辟空間時(shí)的選擇而變動(dòng)
}
??
??
vector(const vector& v)
:_start(nullptr)
,_finish(nullptr)
,_end_of_storage(nullptr)
{ reserve(v.size());
for (const auto& e : v)
{ push_back(e);//this.push_back()
}
}
??
??
??
??1)、vector構(gòu)造函數(shù):使用迭代器區(qū)間構(gòu)造1.0
??涉及問(wèn)題:
??Ⅰ、能否雙模板嵌套式使用?
??Ⅱ、為什么需要新定義一個(gè)模板InputIterator
,而不使用原先的Iterator
?
templatevector(InputIterator first, InputIterator last)
{ while (first != last)
{ push_bakc(*first);
++first;
}
}
void test_vector7()
{string str("hello world");
vectorv(str.begin(), str.end());//使用迭代器區(qū)間構(gòu)造
for (auto e : v)
{ cout<< e<< " ";
}
cout<< endl;
}
??上述代碼是否會(huì)存在什么問(wèn)題?
??回答:_start
、_finish
、_end_of_storage
沒(méi)有初始化,在有些編譯器下其是隨機(jī)值,那么reserve
開(kāi)辟空間時(shí),此處非空就會(huì)拷貝數(shù)據(jù)、釋放空間、存在越界問(wèn)題。
??
??2)、vector構(gòu)造函數(shù):使用迭代器區(qū)間構(gòu)造2.0
??_start
、_finish
、_end_of_storage
初始化為空。
//使用迭代區(qū)間的構(gòu)造函數(shù):含類模板
templatevector(InputIterator first, InputIterator last)
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{ while (first != last)
{ push_back(*first);
++first;
}
}
??
??
void swap(vector& v)
{ std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v.__end_of_storage);
}
vector(const vector& v)
:_start(nullptr)
,_finish(nullptr)
,_end_of_storage(nullptr)
{ vectortmp(v.begin(), v.end());
swap(tmp);
}
??
??
??
??
??1)、模擬實(shí)現(xiàn)及細(xì)節(jié)解析
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);
}
}
??對(duì)const T& val = T()
,實(shí)際上這個(gè)函數(shù)使用了半缺省參數(shù),其缺省值是T()
,一個(gè)T類型的匿名對(duì)象。
????Ⅰ、假若T()
是自定義類型,則調(diào)用自定義類型的默認(rèn)構(gòu)造(事實(shí)上內(nèi)置類型也有模板參數(shù))
????Ⅱ、假若T()
是內(nèi)置類型,因C++中模板的出現(xiàn),也擁有對(duì)應(yīng)的默認(rèn)構(gòu)造函數(shù),此處以int舉例。
void test_vector9()
{int i=11;
int j = int();
int k(10);
cout<< "i:"<< i<< endl;
cout<< "j:"<< j<< endl;
cout<< "k:"<< k<< endl;
}
??
??
??2)、演示
void test_vector10()
{vectorv1(10);//驗(yàn)證默認(rèn)缺省值
for (auto e : v1)
{ cout<< e<< " ";
}
cout<< endl;
vectorv2(5);
for (auto e : v2)
{ cout<< e<< " ";
}
cout<< endl;
}
??
??
??3)、一個(gè)錯(cuò)誤說(shuō)明
vectorv1(10,1);//驗(yàn)證默認(rèn)缺省值
for (auto e : v1)
{ cout<< e<< " ";
}
cout<< endl;
??為什么在該函數(shù)中輸入兩個(gè)int類型的變量會(huì)顯示如下錯(cuò)誤,且報(bào)錯(cuò)還是報(bào)在我們之前寫(xiě)的迭代器區(qū)間構(gòu)造上?
??原因解釋:類型匹配。相比于(size_t
、T
)類型,(InputIterator
、InputIterator
)更匹配(int、int)
。
??
??解決方法:
??①?gòu)?qiáng)制類型轉(zhuǎn)換:vector
;
??②修改函數(shù)形參類型:vector(int n, const T& val = T())
??③使用函數(shù)重載:
vector(int 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);
}
}
??
??
//賦值v1=v2
vector& operator=(vectorv)
{ swap(v);
return *this;
}
??
??
??
??1)、問(wèn)題引入
??在vector(一)中,我們?cè)鴮?xiě)過(guò)楊輝三角:其涉及到了vector
嵌套使用。
class Solution {public:
vector>generate(int numRows) {vector>vv;//定義一個(gè)vector>類型的數(shù)據(jù)
vv.resize(numRows);//第一次開(kāi)辟空間:numRows,表示總行數(shù)(整體大小)
for(size_t i=0;ivv[i].resize(i+1,0);//第二次開(kāi)辟空間,表示初始化楊輝三角的每行大小
vv[i].front()=vv[i].back()=1;//楊輝三vv.size()角每行首尾數(shù)據(jù)為1
//vv[i].resize(i+1,1);//上述代碼也可以合并為一行實(shí)現(xiàn)
}
for(size_t i=2;ifor(size_t j=1;jvv[i][j]=vv[i-1][j-1]+vv[i-1][j];
}
}
return vv;
}
};
vector>ret = Solution().generate(5);
??在使用std中的vector時(shí),這段代碼成功運(yùn)行。而將其放入我們自己實(shí)現(xiàn)的vector中,則會(huì)發(fā)現(xiàn)運(yùn)行失敗。
??為什么我們自己的模擬實(shí)現(xiàn)的vector會(huì)失敗呢?
??Ⅰ、對(duì)vector
,如果我們不傳值返回ector
則運(yùn)行成功,而傳值返回運(yùn)行失敗。需要注意的是,此處傳值返回涉及自定義類型,存在數(shù)據(jù)拷貝的問(wèn)題。
??Ⅱ、基于此我們調(diào)試發(fā)現(xiàn):外層的vector深拷貝成功(值一致、地址空間不一致),而內(nèi)存的vector居然是淺拷貝。
??以上是現(xiàn)象,現(xiàn)在來(lái)分析情況:
??①自定義類型傳值返回,中間生成一個(gè)臨時(shí)變量,涉及深淺拷貝問(wèn)題。
??②拷貝構(gòu)造我們模擬實(shí)現(xiàn)了兩類,一類是傳統(tǒng)寫(xiě)法,使用了memcpy,由上述圖二可知,memcpy是淺拷貝,那么就涉及到同一空間析構(gòu)兩次的問(wèn)題。修改方法如下:
vector(const vector& v)//拷貝構(gòu)造傳統(tǒng)寫(xiě)法
{ _start = new T[v.size()];//此處也可以開(kāi)辟v.capacity()大小的空間,各有各的優(yōu)缺點(diǎn)
//memcpy(_start, v._start, sizeof(T)*v.size());//照搬數(shù)據(jù)
for (size_t i = 0; i< sz; i++)//照搬數(shù)據(jù)
{ _start[i] = v._start[i];//此處假若是自定義類型,則是賦值運(yùn)算符
}
_finish = _start + v.size();
_end_of_storage = _start + v.size();//此處this._finish的大小根據(jù)上述我們開(kāi)辟空間時(shí)的選擇而變動(dòng)
}
??③假若使用的是現(xiàn)代寫(xiě)法,在我們寫(xiě)的兩個(gè)以swap為交換的拷貝構(gòu)造,都沒(méi)問(wèn)題。此處出現(xiàn)問(wèn)題的是擴(kuò)容。原先我們寫(xiě)的擴(kuò)容函數(shù)中用了memcpy,同樣是淺拷貝導(dǎo)致。修改方法如下:
void reserve(size_t n)
{ if (n >capacity())//滿足該條件才進(jìn)行擴(kuò)容
{ size_t sz = size();//因?yàn)楹罄m(xù)重新確定指向關(guān)系時(shí)需要知道size值
T* tmp = new T[n];
if (_start)//說(shuō)明原先空間有數(shù)據(jù),
{//memcpy(tmp, _start, sizeof(T) * sz);//需要挪動(dòng)
for (size_t i = 0; i< sz; i++)//需要挪動(dòng)
{tmp[i] = _start[i];
//*(tmp + i) = *(_start + i);
}
delete[] _start;//釋放舊空間
}
//重新確定指向關(guān)系
_start = tmp;
_finish = _start + sz;
//_finish = _start + size();//如果是在這里獲取size值,則在原先空間有數(shù)據(jù)的情況下,_start已經(jīng)被delete
_end_of_storage = _start + n;
}
}
??
??
??
??
??
??
??
??
??
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
本文題目:【ONE·C++||vector(二)】-創(chuàng)新互聯(lián)
新聞來(lái)源:http://m.rwnh.cn/article16/dsdedg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信公眾號(hào)、企業(yè)網(wǎng)站制作、網(wǎng)站建設(shè)、定制網(wǎng)站、品牌網(wǎng)站設(shè)計(jì)、外貿(mào)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容
網(wǎng)頁(yè)設(shè)計(jì)公司知識(shí)