??學(xué)習(xí)筆記,慢慢補(bǔ)充。
創(chuàng)新互聯(lián)主要從事網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、網(wǎng)頁設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)盂縣,10余年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):18980820575文章目錄??1)、問題引入:
int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{static int staticVar = 1;
int localVar = 1;
int num1[10] = {1, 2, 3, 4 };
char char2[] = "abcd";
const char* pChar3 = "abcd";
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)calloc(4, sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
free(ptr1);
free(ptr3);
}
選擇題:
??選項(xiàng): A、棧??B、堆 ??C、數(shù)據(jù)段(靜態(tài)區(qū)) ??D、代碼段(常量區(qū))
??1、globalVar
在哪里?____ ??staticGlobalVar
在哪里?____
??2、staticVar
在哪里?____ ??localVar
在哪里?____
??3、num1
在哪里?____
??4、char2
在哪里?____ ??*char2
在哪里?___
??5、pChar3
在哪里?____ ??*pChar3
在哪里?____
??6、ptr1
在哪里?____ ??*ptr1
在哪里?____
填空題:
??1、填空題:
??sizeof(num1)
= ____??
??sizeof(char2)
= ____??strlen(char2)
= ____??
??sizeof(pChar3)
= ____??strlen(pChar3)
= ____??
??sizeof(ptr1)
= ____??
??3、 sizeof 和 strlen 區(qū)別?
??
??
??
??2)、劃分區(qū)域示意圖:
??
??
??
??此處詳細(xì)講解請(qǐng)看C動(dòng)態(tài)內(nèi)存章。
??
??
??1)、C++可以兼容C,為什么還需要提出自己的內(nèi)存管理方式?
?? 1、首先要明確的是,C++兼容C,故malloc、calloc、rellaooc、free這些在C++中照樣可以用。
?? 2、但有些地方,C中的動(dòng)態(tài)內(nèi)存管理方式就無能為力,而且使用起來比較麻煩,因此C++又提出了自己的內(nèi)存管理方式:通過new和delete操作符進(jìn)行動(dòng)態(tài)內(nèi)存管理
??
??
??
2.2.1、針對(duì)內(nèi)置類型??1)、new、delete操作符針對(duì)內(nèi)置類型進(jìn)行動(dòng)態(tài)內(nèi)存管理的基本用法
?? 1、首先要明確的是,new、delete是關(guān)鍵字。而C語言中那套動(dòng)態(tài)內(nèi)存管理依賴的是函數(shù)。
如何開辟空間?
void Test()
{// 動(dòng)態(tài)申請(qǐng)一個(gè)int類型的空間
int* ptr4 = new int;
// 動(dòng)態(tài)申請(qǐng)一個(gè)int類型的空間并初始化為10
int* ptr5 = new int(10);
// 動(dòng)態(tài)申請(qǐng)10個(gè)int類型的空間
int* ptr6 = new int[10];
}
int main(void)
{Test();
return 0;
}
?? 如何使用new開辟數(shù)組類型的空間?(即一次性同時(shí)生成多個(gè)類型相同的元素)
?? 該問題C++98不支持,C++11才支持,書寫方法如下:
void Test()
{//C++11:
int* ptr1 = new int[10]{1,2,3 };
}
int main(void)
{Test();
return 0;
}
??
??
如何釋放空間?
void Test()
{// 動(dòng)態(tài)申請(qǐng)一個(gè)int類型的空間
int* ptr4 = new int;
// 動(dòng)態(tài)申請(qǐng)一個(gè)int類型的空間并初始化為10
int* ptr5 = new int(10);
// 動(dòng)態(tài)申請(qǐng)10個(gè)int類型的空間
int* ptr6 = new int[10];
delete ptr4;
delete ptr5;
delete[] ptr6;//單個(gè)對(duì)象直接delete,若是多個(gè)對(duì)象則使用[ ]
//C++11:
int* ptr1 = new int[10]{1,2,3 };
delete[] ptr1;//單個(gè)對(duì)象直接delete,若是多個(gè)對(duì)象則使用[ ]
}
int main(void)
{Test();
return 0;
}
??總結(jié):針對(duì)內(nèi)置類型,new、delete
跟malloc、free
沒有本質(zhì)的區(qū)別,只有用法的區(qū)別。new、delete
用法相對(duì)簡(jiǎn)化了。
??
??
??
??1)、new、delete針對(duì)自定義類型進(jìn)行動(dòng)態(tài)內(nèi)存管理的基本方法
class A
{public:
A(int a = 0)
: _a(a)
{cout<< "A():"<< this<< endl;
}
~A()
{cout<< "~A():"<< this<< endl;
}
private:
int _a;
};
int main()
{// 1、堆上申請(qǐng)空間
A* p1 = (A*)malloc(sizeof(A));
if (p1 == NULL)
{perror("malloc fail");
return 0;
}
// 1、釋放空間
free(p1);
// 1、堆上申請(qǐng)空間 2、調(diào)用構(gòu)造函數(shù)初始化
A* p2 = new A;
A* p2 = new A(10);
// 1、調(diào)用析構(gòu)函數(shù)清理對(duì)象中資源 2、釋放空間
delete p2;
cout<< endl<< endl;
A* p3 = new A[2];
delete[] p3;
//C++11支持
A* p3 = new A[2]{1,2 };
A* p3 = new A[2]{A(1), A(2) };
// 結(jié)論:new/delete 是為自定義類型準(zhǔn)備的。
// 不僅在對(duì)申請(qǐng)出來,還會(huì)調(diào)用構(gòu)造和析構(gòu)初始化和清理
return 0;
}
malloc、free對(duì)自定義類型
?? 1、對(duì)自定義類型使用malloc、free申請(qǐng)和釋放空間:并不會(huì)對(duì)自定義類型初始化。
// 1、堆上申請(qǐng)空間
A* p1 = (A*)malloc(sizeof(A));
if (p1 == NULL)
{perror("malloc fail");
return 0;
}
// 1、釋放空間
free(p1);
new、delete對(duì)自定義類型
?? 1、使用new動(dòng)態(tài)申請(qǐng)自定義類型,會(huì)調(diào)用默認(rèn)構(gòu)造函數(shù)初始化。
?? 2、若類不提供默認(rèn)構(gòu)造,若要編譯通過,則需要自己傳參。
// 1、堆上申請(qǐng)空間 2、調(diào)用構(gòu)造函數(shù)初始化
A* p2 = new A;//這種寫法需要有默認(rèn)構(gòu)造
A* p2 = new A(10);//如果沒有默認(rèn)構(gòu)造則需要我們手動(dòng)傳參
delete p2;
?? 3、相比于free,delete會(huì)調(diào)用析構(gòu)函數(shù)清理對(duì)象中的資源(但是否需要這是取決于析構(gòu)函數(shù)本身)
A* p3 = new A[2];
delete[] p3;
??4、若是沒有默認(rèn)構(gòu)造,多個(gè)自定義類型需要傳參的寫法(一種是構(gòu)造(隱式類型)、一種是拷貝構(gòu)造:
//C++11支持
A* p3 = new A[2]{1,2 };
A* p3 = new A[2]{A(1), A(2) };
delete[] p3;
?? 結(jié)論:new/delete 是為自定義類型準(zhǔn)備的。不僅在對(duì)申請(qǐng)出來,還會(huì)調(diào)用構(gòu)造和析構(gòu)初始化和清理.
??
??2)、delete、new構(gòu)造、析構(gòu)順序探索
??對(duì)于多個(gè)自定義類型,此處需要注意構(gòu)造和析構(gòu)的順序,以及在堆上的地址排序。
class A
{public:
A(int a = 0)
: _a(a)
{cout<< "A():"<< this<< endl;
}
~A()
{cout<< "~A():"<< this<< endl;
}
private:
int _a;
};
int main()
{A* p1 = new A[10];
cout<< endl;
delete[] p1;
return 0;
}
??
??
int main()
{//C: 失敗返回NULL
char* p1 = (char*)malloc(1024u * 1024u * 1024u * 2 - 1);//u表示無符號(hào)
//cout<< p1<< endl;//cout自動(dòng)識(shí)別類型,會(huì)先去解引用字符指針,而非取地址。
printf("%p\n", p1);
//C++: new失敗,不需要檢查返回值,他失敗是拋異常
try
{//申請(qǐng)空間失敗的一種寫法:
char* p2 = new char[1024u * 1024u * 1024u * 2 - 1];//此處失敗會(huì)直接跳轉(zhuǎn)后續(xù)catch部分,不會(huì)指向下一行。
printf("%p\n", p2);
///申請(qǐng)空間失敗的另一種方法:
size_t n = 0;
while (1)
{ char* p2 = new char[1024];
++n;
printf("%p->[%d]\n", p2, n);
}
}
catch (const exception& e)//捕獲異常
{cout<< e.what()<< endl;
}
return 0;
}
??
??
??
?? 1、new和delete是用戶進(jìn)行動(dòng)態(tài)內(nèi)存申請(qǐng)和釋放的操作符,operator new 和operator delete是 系統(tǒng)提供的全局函數(shù),new在底層調(diào)用operator new全局函數(shù)來申請(qǐng)空間,delete在底層通過 operator delete全局函數(shù)來釋放空間。
??2、而operator new 實(shí)際也是通過malloc來申請(qǐng)空間,如果 malloc申請(qǐng)空間成功就直接返回,否則執(zhí)行用戶提供的空間不足應(yīng)對(duì)措施,如果用戶提供該措施 就繼續(xù)申請(qǐng),否則就拋異常。operator delete 最終是通過free來釋放空間的。
??
??
??1、 一般情況下不需要對(duì) operator new 和 operator delete進(jìn)行重載,除非在申請(qǐng)和釋放空間時(shí)候有某些特殊的需求。比如:在使用new和delete申請(qǐng)和釋放空間時(shí),打印一些日志信息,可以簡(jiǎn)單幫助用戶來檢測(cè)是否存在內(nèi)存泄漏。
??2、關(guān)于專屬的operator new的實(shí)現(xiàn):可用于頻繁調(diào)用new需要提高效率的情況
// new ->operator new + 構(gòu)造函數(shù)
// 默認(rèn)情況下operator new使用全局庫里面
// 每個(gè)類可以去實(shí)現(xiàn)自己專屬operator new new這個(gè)類對(duì)象,就會(huì)調(diào)自己實(shí)現(xiàn)這個(gè)operator new
// 實(shí)現(xiàn)一個(gè)類專屬的operator new -- 了解一下
struct ListNode
{int _val;
ListNode* _next;
// 內(nèi)存池
static allocatoralloc;//靜態(tài)成員變量
void* operator new(size_t n)//重載專屬的operator new
{cout<< "operator new ->STL內(nèi)存池allocator申請(qǐng)"<< endl;
void* obj = alloc.allocate(1);
return obj;
}
void operator delete(void* ptr)//重載專屬的operator delete
{cout<< "operator delete ->STL內(nèi)存池allocator申請(qǐng)"<< endl;
alloc.deallocate((ListNode*)ptr, 1);
}
struct ListNode(int val)
:_val(val)
, _next(nullptr)
{}
};
// allocator以后會(huì)講,現(xiàn)在先會(huì)用即可
allocatorListNode::alloc;//類外定義
int main()
{// 頻繁申請(qǐng)ListNode. 想提高效率 -- 申請(qǐng)ListNode時(shí),不去malloc,而是自己定制內(nèi)存池
ListNode* node1 = new ListNode(1);//new相對(duì)于malloc簡(jiǎn)化
ListNode* node2 = new ListNode(2);
ListNode* node3 = new ListNode(3);
delete node1;
delete node2;
delete node3;
return 0;
}
??
??
??
??
??1)、場(chǎng)景引入:
class A
{public:
A(int a = 0)
: _a(a)
{cout<< "A():"<< this<< endl;
}
~A()
{cout<< "~A():"<< this<< endl;
}
private:
int _a;
};
int main()
{A* p1 = new A;
A* p2 = (A*)malloc(sizeof(A));
if (p2 == nullptr)
{perror("malloc fail");
}
return 0;
}
??如上述代碼:有時(shí)我們需要對(duì)已經(jīng)定義的類進(jìn)行初始化。而我們知道,類初始化需要調(diào)用構(gòu)造函數(shù),目前已知的兩種構(gòu)造函數(shù)調(diào)用方式是,①在定義類時(shí)會(huì)調(diào)用構(gòu)造函數(shù)初始化成員;②通過new開辟自定義類型也會(huì)進(jìn)過構(gòu)造函數(shù)。
??那么,針對(duì)上述p2這樣已經(jīng)申請(qǐng)好的類,成員變量私有情況下,如何為它初始化?
??
??2)、是什么和怎么用:
??概念:
??定位new表達(dá)式是在已分配的原始內(nèi)存空間中調(diào)用構(gòu)造函數(shù)初始化一個(gè)對(duì)象。
??使用格式:
??new (place_address) type
或者new (place_address) type(initializer-list)
??①place_address
必須是一個(gè)指針
??②initializer-list
是類型的初始化列表
??
?? 演示:
new(p2)A;
new(p2)A(10);
class A
{public:
A(int a = 0)
: _a(a)
{cout<< "A():"<< this<< endl;
}
~A()
{cout<< "~A():"<< this<< endl;
}
private:
int _a;
};
int main()
{A* p1 = new A;
A* p2 = (A*)malloc(sizeof(A));
if (p2 == nullptr)
{perror("malloc fail");
}
new(p2)A;//方法一
new(p2)A(10);//方法二
return 0;
}
??
??3)、為什么用:
??使用場(chǎng)景:
??定位new表達(dá)式在實(shí)際中一般是配合內(nèi)存池使用。因?yàn)閮?nèi)存池分配出的內(nèi)存沒有初始化,所以如果是自定義類型的對(duì)象,需要使用new的定義表達(dá)式進(jìn)行顯示調(diào)構(gòu)造函數(shù)進(jìn)行初始化。
??
??
??
??1)、關(guān)于為什么要有泛型編程的引入說明:
void Swap(int& left, int& right)
{int temp = left;
left = right;
right = temp;
}
void Swap(double& left, double& right)
{double temp = left;
left = right;
right = temp;
}
void Swap(char& left, char& right)
{char temp = left;
left = right;
right = temp;
}
int main()
{int i = 1, j = 2;
double x = 1.1, y = 2.2;
Swap(i, j);
Swap(x, y);
char m = 'A', n = 'B';
Swap(m, n);
return 0;
}
?? 類似于上述Swap交換函數(shù),雖然我們也可以通過typedef重命名來更換類型,但如果出現(xiàn)多個(gè)類型同時(shí)需要使用Swap函數(shù)時(shí),typedef仍舊不能很好的解決問題。
?? 因此,我們提出了泛型編程。
??泛型編程: 編寫與類型無關(guān)的通用代碼,是代碼復(fù)用的一種手段。模板是泛型編程的基礎(chǔ)。
??
??
??
??
??template
??返回值類型 函數(shù)名(參數(shù)列表){}
?? 實(shí)例演示:
templatevoid Swap(T& left, T& right)
{T tmp = left;
left = right;
right = tmp;
}
?? 1、typename后面類型名字T是隨便取,Ty、K、V,一般是大寫字母或者單詞首字母大寫
??2、T 代表是一個(gè)模板類型(虛擬類型)
??3、注意:typename
是用來定義模板參數(shù)關(guān)鍵字,也可以使用class
(切記:不能使用struct代替class)
template//此處typename與class只有一些細(xì)微區(qū)別,后面再講述
void Swap(T& left, T& right)
{T tmp = left;
left = right;
right = tmp;
}
??演示如下:此處有一個(gè)問題,我們用不同類型的變量去調(diào)用這個(gè)函數(shù)模板時(shí),所生成的Swap函數(shù)是不是同一個(gè)?
??
??
??1)、問題引入:
??接上文:
??
??2)、總述:
??
??
??1)、函數(shù)模板實(shí)例化·隱式實(shí)例化中一個(gè)容易出錯(cuò)的問題
templateT Add(const T& left, const T& right)
{return left + right;
}
int main()
{int a1 = 10, a2 = 20;
double d1 = 10.0, d2 = 20.0;
Add(a1, a2);//right
Add(d1, d2);//right
Add(a1, d1);//error
return 0;
}
??隱式實(shí)例化中編譯報(bào)錯(cuò)的場(chǎng)景之一:
??報(bào)錯(cuò)原因并非不能隱式類型轉(zhuǎn)換(事實(shí)上C++沿襲C,不用模板我們自己寫Add時(shí)是成功的),此處報(bào)錯(cuò)的真正原因在于推演實(shí)例化報(bào)錯(cuò)。即無法確定需要轉(zhuǎn)換到哪個(gè)類型。
??
??
??2)、如何解決隱式實(shí)例化中這類問題?
解決方案一:強(qiáng)制類型轉(zhuǎn)換
??演示如下:
templateT Add(const T& left, const T& right)
{return left + right;
}
int main()
{//編譯器自動(dòng)推演,隱式實(shí)例化
cout<< Add(1, 2)<< endl;
cout<< Add((int)1.1, 2)<< endl;
cout<< Add(1.1, (double)2)<< endl;
return 0;
}
??
??
解決方案二:顯示實(shí)例化
??顯式實(shí)例化:在函數(shù)名后的<>中指定模板參數(shù)的實(shí)際類型
templateT Add(const T& left, const T& right)
{return left + right;
}
int main()
{//顯式實(shí)例化:在函數(shù)名后的<>中指定模板參數(shù)的實(shí)際類型
cout<< Add(1, 2)<< endl;
cout<< Add(1.1, 2)<< endl;
cout<< Add(1.1, 2)<< endl;
return 0;
}
??1、此處模板類型有幾個(gè),顯示實(shí)例化時(shí),實(shí)際類型就要寫幾個(gè)。
??2、如果類型不匹配,編譯器會(huì)嘗試進(jìn)行隱式類型轉(zhuǎn)換,如果無法轉(zhuǎn)換成功編譯器將會(huì)報(bào)錯(cuò)。
??
??
??
解決方案三:使用多個(gè)模板類型
templateT1 Add(const T1& left, const T2& right)
{return left + right;
}
int main()
{cout<< Add(1, 2)<< endl;
cout<< Add(1.1, 2)<< endl;
cout<< Add(2, 1.1)<< endl;//要注意理解此處細(xì)節(jié):參與Add時(shí)仍舊會(huì)發(fā)生隱式類型轉(zhuǎn)換為double,只是返回類型為int
return 0;
}
??
??
??3)、一些必須顯示實(shí)例化的場(chǎng)景說明
templateT* Func(int n)
{T* a = new T[n];
return a;
}
class A{};
int main()
{// 必須顯示實(shí)例化才能調(diào)用
Func(10);//此處是因?yàn)閭魅氲膮?shù)為int型,而實(shí)際T需要返回類型為類A,因此在此處指定實(shí)際類型為A。
return 0;
}
3.2.4、模板參數(shù)的匹配原則??1)、關(guān)于函數(shù)模板、非模板函數(shù)同時(shí)存在時(shí),如何調(diào)用的問題?
??回答:如何有匹配的非模板函數(shù),率先調(diào)用該函數(shù),若沒有,則調(diào)用模板函數(shù)。
??
演示實(shí)例一:
?? 一個(gè)非模板函數(shù)可以和一個(gè)同名的函數(shù)模板同時(shí)存在,而且該函數(shù)模板還可以被實(shí)例化為這個(gè)非模板函數(shù)。
// 專門處理int的加法函數(shù)
int Add(int left, int right)
{return left + right;
}
// 通用加法函數(shù)
templateT Add(T left, T right)
{return left + right;
}
void Test()
{Add(1, 2); // 有匹配的非模板函數(shù),不會(huì)調(diào)用模板
Add(1.1, 2.2);// 沒有匹配的非模板函數(shù),會(huì)去調(diào)用模板
Add(1, 2); // 調(diào)用編譯器特化的模板
}
int main()
{Test();
return 0;
}
??
演示實(shí)例二:
?? 對(duì)于非模板函數(shù)和同名函數(shù)模板,如果其他條件都相同,在調(diào)動(dòng)時(shí)會(huì)優(yōu)先調(diào)用非模板函數(shù)而不會(huì)從該模板產(chǎn)生出一個(gè)實(shí)例。如果模板可以產(chǎn)生一個(gè)具有更好匹配的函數(shù), 那么將選擇模板。
// 專門處理int的加法函數(shù)
int Add(int left, int right)
{return left + right;
}
// 通用加法函數(shù)
templateT1 Add(T1 left, T2 right)
{return left + right;
}
void Test()
{Add(1, 2); // 與非函數(shù)模板類型完全匹配,不需要函數(shù)模板實(shí)例化
Add(1, 2.0); // 模板函數(shù)可以生成更加匹配的版本,編譯器根據(jù)實(shí)參生成更加匹配的Add函數(shù)
}
int main()
{Test();
return 0;
}
??
??
??1)、為什么需要類模板的引入?
class Stacki
{private:
int* _a;
int top;
int capacity;
};
class Stackc
{private:
char* _a;
int top;
int capacity;
};
int main()
{Stackc st1; // char
Stacki st2; // int
return 0;
}
typedef char STDataType;//此處修改類型
class Stack
{private:
STDataType* _a;
int top;
int capacity;
};
int main()
{Stack st1; // char
Stack st2; // char
return 0;
}
??
??
??2)、類模板如何使用?
?? 類模板格式說明:
templateclass 類模板名
{// 類內(nèi)成員定義
};
??
??3)、以類模板定義Stack舉例說明使用細(xì)節(jié):各類知識(shí)雜糅與理解
??總體演示:
template//用模板定義一個(gè)類
class Stack
{public:
//構(gòu)造函數(shù)
Stack(size_t capacity = 4)//缺省值
: _a(nulltpr)//初始化列表:默認(rèn)先處理為這樣子
, _top(0)
, _capacity(0)
{if (capacity >0)//雖然給了缺省值,但也有可能實(shí)參傳遞進(jìn)來的是0
{ //為_a開辟空間,此處使用了new,注意new的用法以及new多個(gè)空間時(shí)[]中傳入的數(shù)據(jù)
_a = new T[capacity];//此處不需要檢查new是否失敗,因?yàn)榭梢允褂脪伄惓ry\catch
_capacity = capacity;
_top = 0;
}
}
private:
T* _a;
size_t _top;
size_t _capacity;
};
int main()
{//用同一個(gè)類模板顯示實(shí)例化
//不過Stack、Stack是不同的兩個(gè)類型
Stackstr1;
Stackstr2;
//關(guān)于缺省值:如果我們能具體知道capacity值,就能這樣直接傳入
//若不知曉,就可以使用缺省值中給定的。
Stackstr3(100);
//關(guān)于初始化列表中的_capacity是為了處理這樣的情況:
Stackstr4(0);
//若沒有它,上述構(gòu)造函數(shù)中進(jìn)不了if語句,而_capacity沒有初始化,
//那么得到的str4實(shí)際上_capacity得到的是默認(rèn)隨機(jī)值,
//而我們插入數(shù)據(jù)時(shí)擴(kuò)容卻是看_top==_capacity的
//這樣就出了問題
}
??細(xì)節(jié)解釋一:自定義類型的模板定義需要顯式實(shí)例化:即這里需要理解模板定義出來的類型T需要用到哪里。
//用同一個(gè)類模板顯式實(shí)例化
//不過Stack、Stack是不同的兩個(gè)類型
Stackstr1;
Stackstr2;
??細(xì)節(jié)解釋二:初始化列表處,_capacity(0)
這些是否要處理?
Stack(size_t capacity = 4)//缺省值
: _a(nulltpr)//初始化列表:
, _top(0)
, _capacity(0)
{}
??回答:需要。構(gòu)造函數(shù)中我們給予的只是缺省值,如果顯示穿參并且參數(shù)為0時(shí),會(huì)導(dǎo)致_capacity
處為隨機(jī)值,那么后續(xù)會(huì)遇到各種麻煩。
//關(guān)于初始化列表中的_capacity是為了處理這樣的情況:
Stackstr4(0);
//若沒有它,上述構(gòu)造函數(shù)中進(jìn)不了if語句,而_capacity沒有初始化,
//那么得到的str4實(shí)際上_capacity得到的是默認(rèn)隨機(jī)值,
//而我們插入數(shù)據(jù)時(shí)擴(kuò)容卻是看_top==_capacity的
//這樣就出了問題
??細(xì)節(jié)解釋三:如果不在初始化列表給值,也可以在private成員變量中給,即使用C++打的補(bǔ)丁,但本質(zhì)上是一樣的。
private:
T* _a =nullptr;
size_t _top =0;
size_t _capacity =0;
??
??
??模板不支持聲明和定義跨文件分離。若是覺得放在類中形成內(nèi)聯(lián)不方便,則可在同文件中進(jìn)行聲明和定義分離。
??同文件中的聲明和定義分離,注意類模板的寫法。
??
??
??
templateclass Stack
{public:
//構(gòu)造函數(shù)
Stack(size_t capacity = 4)//缺省值
:_a(nulltpr)//初始化列表:默認(rèn)先處理為這樣子
, _top(0)
, _capacity(0)
{if (capacity >0)//雖然給了缺省值,但也有可能實(shí)參傳遞進(jìn)來的是0
{ //為_a開辟空間,此處使用了new,注意new的用法以及new多個(gè)空間時(shí)[]中傳入的數(shù)據(jù)
_a = new T[capacity];//此處不需要檢查new是否失敗,因?yàn)榭梢允褂脪伄惓ry\catch
_capacity = capacity;
_top = 0;
}
}
//析構(gòu)函數(shù)
~Stack()
{//需要手動(dòng)釋放動(dòng)態(tài)內(nèi)存空間
delete[] _a;//使用delete時(shí)需要注意加括號(hào)
//后續(xù)置空這個(gè)步驟不影響
_a = nullptr;
_capacity = _top = 0;
}
//拷貝構(gòu)造:此處設(shè)計(jì)深淺拷貝,后續(xù)講解
void Push(const T& x);//此處再次體現(xiàn)泛型模板,因?yàn)椴迦霐?shù)據(jù)類型為T
//刪除
void Pop()
{assert(_top >0);
--_top;
}
//判空
bool Empty()
{return _top == 0;
}
//取棧頂元素
const T& Top()
{//此處_a中的數(shù)據(jù)屬于堆上動(dòng)態(tài)開辟的,因此可以使用引用傳值返回
//此處加入const是為了防止引用返回后將棧頂元素修改
assert(_top >0);
return _a[_top - 1];
}
private:
T* _a;
size_t _top;
size_t _capacity;
};
//棧頂插入:
//此處再次體現(xiàn)泛型模板,因?yàn)椴迦霐?shù)據(jù)類型為T
{//檢查擴(kuò)容
//有兩種可能性:第一,空間已滿;第二,空間未開辟
if (_top == _capacity)
{// 1、開新空間
// 2、拷貝數(shù)據(jù)
// 3、釋放舊空間
size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
//擴(kuò)容需要重新開辟空間,以前我們學(xué)習(xí)的是malloc和realloc,能原地?cái)U(kuò)容或者系統(tǒng)自己解決
//現(xiàn)在我們使用new、delete,其不能自動(dòng)解決空間問題,因此需要我們手動(dòng)處理
T* tmp = new T[newcapacity];
//引出問題:為什么C++中我們推薦使用new、delet?
//回答:此處使用的是類模板,其模板類型T有可能是自定義類型
//malloc對(duì)自定義類型在申請(qǐng)空間時(shí)不會(huì)初始化。
//開了新空間,需要對(duì)舊空間進(jìn)行處理
if (_a)//這里是用來檢查是否為第一次擴(kuò)容,因?yàn)槭状螖U(kuò)容就不存在搬動(dòng)空間問題
{ //要將舊空間中的數(shù)據(jù)拷貝到新空間里
memcpy(tmp, _a, sizeof(T) * _top);//注意memcpy的使用參數(shù)含義
//釋放舊空間
delet[] _a;
}
//改變指向關(guān)系
_a = tmp;
_capacity = newcapacity;
}
_a[_top] = x;
++_top;
}
??
??
??
??
??
你是否還在尋找穩(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++||內(nèi)存管理和模板初階】-創(chuàng)新互聯(lián)
鏈接地址:http://aaarwkj.com/article0/codgoo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供響應(yīng)式網(wǎng)站、網(wǎng)站設(shè)計(jì)公司、網(wǎng)頁設(shè)計(jì)公司、品牌網(wǎng)站建設(shè)、網(wǎng)站維護(hù)、建站公司
聲明:本網(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í)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容