C++超詳細講解auto與nullptr的使用
一. auto關(guān)鍵字
1. auto介紹
在早期C/C++中auto的含義是:使用auto修飾的變量,是具有自動存儲器的局部變量。
但是在C++11開始,賦予了auto全新的含義即:auto不再是一個存儲類型指示符,而是作為一個新的類型指示符來指示編譯器,auto聲明的變量必須由編譯器在編譯時期推導(dǎo)而得。
int TestAuto() { return 10; } int main() { int a = 10; auto b = a; auto c = 'a'; auto d = TestAuto(); //打印類型 cout << typeid(b).name() << endl; cout << typeid(c).name() << endl; cout << typeid(d).name() << endl; return 0; }
注意:
使用auto定義變量時必須對其進行初始化,在編譯階段編譯器需要根據(jù)初始化表達式來推導(dǎo)auto的實際類型。因此auto并非是一種“類型”的聲明,而是一個類型聲明時的“占位符”,編譯器在編譯期會將auto替換為變量實際的類型(自定義類型也可以)。
auto a; 無法通過編譯,使用auto定義變量時必須對其進行初始化
2. 使用規(guī)則
(1)auto與指針和引用結(jié)合起來使用
用auto聲明指針類型時,用auto和auto*沒有任何區(qū)別,但用auto聲明引用類型時則必須加&
int main() { int x = 10; const int y = 20; //推斷沒有帶解引用操作符的整形指針 auto a = &x; auto a2 = &y; //推斷帶解引用操作符的整形指針 auto* b = &x; //auto* b = x;//注意別寫成這樣,左邊推導(dǎo)一定是指針,x是整形,這樣是會報錯的 auto* b2 = &y; //推斷引用類型 auto& c = x; auto& c2 = y; //打印類型 cout << typeid(a).name() << endl; cout << typeid(b).name() << endl; cout << typeid(c).name() << endl; cout << typeid(a2).name() << endl; cout << typeid(b2).name() << endl; cout << typeid(c2).name() << endl; return 0; }
這里發(fā)現(xiàn)了一個問題,我們用const修飾了y,但是推導(dǎo)出來的引用類型居然沒有被const修飾,但是我們在寫代碼的時候不加const編譯器一定會報錯,要注意這里的這個問題
(2)在同一行定義多個變量
當(dāng)在同一行聲明多個變量時,這些變量必須是相同的類型,否則編譯器將會報錯,因為編譯器實際只對第一個類型進行推導(dǎo),然后用推導(dǎo)出來的類型定義其他變量。
void TestAuto() { auto a = 1, b = 2; auto c = 3, d = 4.0; // 該行代碼會編譯失敗,因為c和d的初始化表達式類型不同 }
3. auto不能推導(dǎo)的場景
auto不能作為函數(shù)的參數(shù)和返回值
// 此處代碼編譯失敗,auto不能作為形參類型,因為編譯器無法對a的實際類型進行推導(dǎo) void TestAuto(auto a) {} //不然接收和傳參不知道怎么傳參和接收 auto TestAuto(int a) {}
auto不能直接用來聲明數(shù)組
void TestAuto() { int a[] = {1,2,3}; auto b[] = {4,5,6}; }
為了避免與C++98中的auto發(fā)生混淆,C++11只保留了auto作為類型指示符的用法
auto在實際中最常見的優(yōu)勢用法就是跟以后會講到的C++11提供的新式for循環(huán),還有l(wèi)ambda表達式等進行配合使用。
二. 基于范圍的for循環(huán)(C++11)
1. 范圍for的語法
在C++98中如果要遍歷一個數(shù)組,可以按照以下方式進行:
void TestFor() { int array[] = { 1, 2, 3, 4, 5 }; for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i) array[i] *= 2; for (int* p = array; p < array + sizeof(array)/ sizeof(array[0]); ++p) cout << *p << endl; }
對于一個有范圍的集合而言,由程序員來說明循環(huán)的范圍是多余的,有時候還會容易犯錯誤。因此C++11中引入了基于范圍的for循環(huán)。for循環(huán)后的括號由冒號“ :”分為兩部分:第一部分是范圍內(nèi)用于迭代的變量, 第二部分則表示被迭代的范圍。
void TestFor() { //依次自動取array中的數(shù)據(jù)賦值給e,自動判斷結(jié)束 int array[] = { 1, 2, 3, 4, 5 }; for(auto& e : array) e *= 2; for(auto e : array) cout << e << " "; }
注意:與普通循環(huán)類似,可以用continue來結(jié)束本次循環(huán),也可以用break來跳出整個循環(huán)。
2. 范圍for的使用條件
(1)for循環(huán)迭代的范圍必須是確定的
對于數(shù)組而言,就是數(shù)組中第一個元素和最后一個元素的范圍;對于類而言,應(yīng)該提供begin和end的方法,begin和end就是for循環(huán)迭代的范圍。
以下代碼就有問題,因為for的范圍不確定:
(數(shù)組傳參,數(shù)組會退化成指針,所以這里接受的是指針,就導(dǎo)致了范圍是不確定的)
void TestFor(int array[]) { for(auto& e : array) cout<< e <<endl; }
(2)迭代的對象要實現(xiàn)++和==的操作
三. 指針空值nullptr(C++11)
C++98中的指針空值,在C/C++中,聲明一個變量時最好給該變量一個合適的初始值,否則可能會出現(xiàn)不可預(yù)料的錯誤,比如未初始化的指針。如果一個指針沒有合法的指向,我們基本都是按照如下方式對其進行初始化:
void TestPtr() { int* p1 = NULL; int* p2 = 0; }
但是,這里的NULL實際是一個宏,在傳統(tǒng)的C頭文件(stddef.h)中,可以看到如下代碼:
#ifndef NULL #ifdef __cplusplus #define NULL 0 #else #define NULL ((void *)0) #endif #endif
可以看到,NULL可能被定義為字面常量0,或者被定義為無類型指針(void*)的常量。但是不論采取何種定義,在使用空值的指針時,都不可避免的會遇到一些麻煩,比如:
void fun(int) { cout<<"fun(int)"<<endl; } void fun(int*) { cout<<"fun(int*)"<<endl; } int main() { fun(0); fun(NULL); fun((int*)NULL); return 0; }
程序本意是想通過fun(NULL)調(diào)用指針版本的fun(int*)函數(shù),但是由于NULL被定義成0,因此與程序的初衷相悖。 在C++98中,字面常量0既可以是一個整形數(shù)字,也可以是無類型的指針(void*)常量,但是編譯器默認(rèn)情況下將其看成是一個整形常量,如果要將其按照指針方式來使用,必須對其進行強轉(zhuǎn)(void *)0。
注意:
- 在使用nullptr表示指針空值時,不需要包含頭文件,因為nullptr是C++11作為新關(guān)鍵字引入的。
- 在C++11中,sizeof(nullptr) 與 sizeof((void*)0)所占的字節(jié)數(shù)相同。
- 為了提高代碼的健壯性,在后續(xù)表示指針空值時建議最好使用nullptr。
到此這篇關(guān)于C++超詳細啊境界auto與nullptr的使用的文章就介紹到這了,更多相關(guān)C++ auto與nullptr內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++?LeetCode1827題解最少操作使數(shù)組遞增
這篇文章主要為大家介紹了C++?LeetCode1827題解最少操作使數(shù)組遞增示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12