国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

【C++從青銅到王者】第二十二篇:C++11

Steven / 1879人閱讀

摘要:不過由于主要是對(duì)標(biāo)準(zhǔn)中的漏洞進(jìn)行修復(fù),語(yǔ)言的核心部分則沒有改動(dòng),因此人們習(xí)慣性的把兩個(gè)標(biāo)準(zhǔn)合并稱為標(biāo)準(zhǔn)。從到,標(biāo)準(zhǔn)年磨一劍,第二個(gè)真正意義上的標(biāo)準(zhǔn)珊珊來遲。

系列文章目錄



前言


一、C++11簡(jiǎn)介(了解)

在2003年C++標(biāo)準(zhǔn)委員會(huì)曾經(jīng)提交了一份技術(shù)勘誤表(簡(jiǎn)稱TC1),使得C++03這個(gè)名字已經(jīng)取代了C++98稱為C++11之前的最新C++標(biāo)準(zhǔn)名稱。不過由于TC1主要是對(duì)C++98標(biāo)準(zhǔn)中的漏洞進(jìn)行修復(fù),語(yǔ)言的核心部分則沒有改動(dòng),因此人們習(xí)慣性的把兩個(gè)標(biāo)準(zhǔn)合并稱為C++98/03標(biāo)準(zhǔn)。從C++0x到C++11,C++標(biāo)準(zhǔn)10年磨一劍,第二個(gè)真正意義上的標(biāo)準(zhǔn)珊珊來遲。相比于C++98/03,C++11則帶來了數(shù)量可觀的變化,其中包含了約140個(gè)新特性,以及對(duì)C++03標(biāo)準(zhǔn)中約600個(gè)缺陷的修正,這使得C++11更像是從C++98/03中孕育出的一種新語(yǔ)言。相比較而言,C++11能更好地用于系統(tǒng)開發(fā)和庫(kù)開發(fā)、語(yǔ)法更加泛華和簡(jiǎn)單化、更加穩(wěn)定和安全,不僅功能更強(qiáng)大,而且能提升程序員的開發(fā)效率。

二、 列表初始化(了解)

1.C++98中{}的初始化問題

在C++98中,標(biāo)準(zhǔn)允許使用花括號(hào){}對(duì)數(shù)組元素進(jìn)行統(tǒng)一的列表初始值設(shè)定。比如:

int array1[] = {1,2,3,4,5};int array2[5] = {0};

對(duì)于一些自定義的類型,卻無法使用這樣的初始化。比如:

vector v{1,2,3,4,5};

就無法通過編譯,導(dǎo)致每次定義vector時(shí),都需要先把vector定義出來,然后使用循環(huán)對(duì)其賦初始值,非常不方便。C++11擴(kuò)大了用大括號(hào)括起的列表(初始化列表)的使用范圍,使其可用于所有的內(nèi)置類型和用戶自定義的類型,使用初始化列表時(shí),可添加等號(hào)(=),也可不添加。

2.內(nèi)置類型的列表初始化

int main(){	// 內(nèi)置類型變量	int x1 = { 10 };	int x2{ 10 };	int x3 = 1 + 2;	int x4 = { 1 + 2 };	int x5{ 1 + 2 };	// 數(shù)組	int arr1[5] {1, 2, 3, 4, 5};	int arr2[]{1, 2, 3, 4, 5};	// 動(dòng)態(tài)數(shù)組,在C++98中不支持	int* arr3 = new int[5]{1, 2, 3, 4, 5};	// 標(biāo)準(zhǔn)容器	vector<int> v{ 1, 2, 3, 4, 5 };	map<int, int> m{ { 1, 1 }, { 2, 2, }, { 3, 3 }, { 4, 4 } };	return 0;}

注意:列表初始化可以在{}之前使用等號(hào),其效果與不使用=沒有什么區(qū)別。

3.自定義類型的列表初始化

標(biāo)準(zhǔn)庫(kù)支持單個(gè)對(duì)象的列表初始化。

class Point{public:	Point(int x = 0, int y = 0) : _x(x), _y(y)	{}private:	int _x;	int _y;};int main(){	Pointer p{ 1, 2 };	return 0;}

多個(gè)對(duì)象的列表初始化:

多個(gè)對(duì)象想要支持列表初始化,需給該類(模板類)添加一個(gè)帶有initializer_list類型參數(shù)的構(gòu)造函數(shù)即可。注意:initializer_list是系統(tǒng)自定義的類模板,該類模板中主要有三個(gè)方法:begin()、end()迭代器以及獲取區(qū)間中元素個(gè)數(shù)的方法size()。

#include template<class T>class Vector {public:	// ...	Vector(initializer_list<T> l) : _capacity(l.size()), _size(0)	{		_array = new T[_capacity];		for (auto e : l)			_array[_size++] = e;	}	Vector<T>& operator=(initializer_list<T> l) {		delete[] _array;		size_t i = 0;		for (auto e : l)			_array[i++] = e;		return *this;	}	// ...private:	T* _array;	size_t _capacity;	size_t _size;};

三、變量類型推導(dǎo)(了解)

1.為什么需要類型推導(dǎo)


在定義變量時(shí),必須先給出變量的實(shí)際類型,編譯器才允許定義,但有些情況下可能不知道需要實(shí)際類型怎么給,或者類型寫起來特別復(fù)雜,比如:

#include #include int main(){	short a = 32670;	short b = 32670;	// c如果給成short,會(huì)造成數(shù)據(jù)丟失,如果能夠讓編譯器根據(jù)a+b的結(jié)果推導(dǎo)c的實(shí)際類型,就不會(huì)存在問題	short c = a + b;	std::map<std::string, std::string> m{ { "apple", "蘋果" }, { "banana", "香蕉" } };	// 使用迭代器遍歷容器, 迭代器類型太繁瑣	std::map<std::string, std::string>::iterator it = m.begin();	while (it != m.end())	{		cout << it->first << " " << it->second << endl;		++it;	}	return 0;}


C++11中,可以使用auto來根據(jù)變量初始化表達(dá)式類型推導(dǎo)變量的實(shí)際類型,可以給程序的書寫提供許多方便。將程序中c與it的類型換成auto,程序可以通過編譯,而且更加簡(jiǎn)潔。關(guān)于auto的詳細(xì)介紹可以參考前面的博客。

2. decltype類型推導(dǎo)

1.為什么需要decltype

auto使用的前提是:必須要對(duì)auto聲明的類型進(jìn)行初始化,否則編譯器無法推導(dǎo)出auto的實(shí)際類型。但有時(shí)候可能需要根據(jù)表達(dá)式運(yùn)行完成之后結(jié)果的類型進(jìn)行推導(dǎo),因?yàn)榫幾g期間,代碼不會(huì)運(yùn)行,此時(shí)auto也就無能為力。

template<class T1, class T2>T1 Add(const T1& left, const T2& right){   	return left + right;}

如果能用加完之后結(jié)果的實(shí)際類型作為函數(shù)的返回值類型就不會(huì)出錯(cuò),但這需要程序運(yùn)行完才能知道結(jié)果的實(shí)際類型,即RTTI(Run-Time Type Identification 運(yùn)行時(shí)類型識(shí)別)。

C++98中確實(shí)已經(jīng)支持RTTI:

  • typeid只能查看類型名字不能用其結(jié)果類定義類型。
  • dynamic_cast只能應(yīng)用于含有虛函數(shù)的繼承體系中。

運(yùn)行時(shí)類型識(shí)別的缺陷是降低程序運(yùn)行的效率。

2. decltype

decltype是根據(jù)表達(dá)式的實(shí)際類型推演出定義變量時(shí)所用的類型,比如:

  • 推演表達(dá)式類型作為變量的定義類型。
int main(){	int a = 10;	int b = 20;	// 用decltype推演a+b的實(shí)際類型,作為定義c的類型	decltype(a + b) c;	cout << typeid(c).name() << endl;	return 0;}
  • 推演函數(shù)返回值的類型:
void* GetMemory(size_t size){	return malloc(size);}int main(){	// 如果沒有帶參數(shù),推導(dǎo)函數(shù)的類型	cout << typeid(decltype(GetMemory)).name() << endl;	// 如果帶參數(shù)列表,推導(dǎo)的是函數(shù)返回值的類型,注意:此處只是推演,不會(huì)執(zhí)行函數(shù)	cout << typeid(decltype(GetMemory(0))).name() << endl;	return 0;}

四、范圍for循環(huán)

參考前面博客:C++入門

五、final與override

六、智能指針

后續(xù)文章講解。

七、新增加容器—靜態(tài)數(shù)組array、forward_list以及unordered系列

八、默認(rèn)成員函數(shù)控制(了解)

在C++中對(duì)于空類編譯器會(huì)生成一些默認(rèn)的成員函數(shù),比如:構(gòu)造函數(shù)、拷貝構(gòu)造函數(shù)、運(yùn)算符重載、析構(gòu)函數(shù)和&和const&的重載、移動(dòng)構(gòu)造、移動(dòng)拷貝構(gòu)造等函數(shù)。如果在類中顯式定義了,編譯器將不會(huì)重新生成默認(rèn)版本。有時(shí)候這樣的規(guī)則可能被忘記,最常見的是聲明了帶參數(shù)的構(gòu)造函數(shù),必要時(shí)則需要定義不帶參數(shù)的版本以實(shí)例化無參的對(duì)象。而且有時(shí)編譯器會(huì)生成,有時(shí)又不生成,容易造成混亂,于是C++11讓程序員可以控制是否需要編譯器生成。

1.顯式缺省函數(shù)


在C++11中,可以在默認(rèn)函數(shù)定義或者聲明時(shí)加上=default,從而顯式的指示編譯器生成該函數(shù)的默認(rèn)版本,用=default修飾的函數(shù)稱為顯式缺省函數(shù)。

class A{public:	A(int a) : _a(a)	{}	// 顯式缺省構(gòu)造函數(shù),由編譯器生成,一定生成	A() = default;	// 在類中聲明,在類外定義時(shí)讓編譯器生成默認(rèn)賦值運(yùn)算符重載	A& operator=(const A& a);private:	int _a;};A& A::operator=(const A& a) = default;int main(){	A a1(10);	A a2;	a2 = a1;	return 0;}

2.刪除默認(rèn)函數(shù)

如果能想要限制某些默認(rèn)函數(shù)的生成,在C++98中,是該函數(shù)設(shè)置成private,并且不給定義,這樣只要其他人想要調(diào)用就會(huì)報(bào)錯(cuò)。在C++11中更簡(jiǎn)單,只需在該函數(shù)聲明加上=delete即可,該語(yǔ)法指示編譯器不生成對(duì)應(yīng)函數(shù)的默認(rèn)版本,稱=delete修飾的函數(shù)為刪除函數(shù)。

class A{public:	A(int a) : _a(a)	{}	// 禁止編譯器生成默認(rèn)的拷貝構(gòu)造函數(shù)以及賦值運(yùn)算符重載	A(const A&) = delete;	A& operator(const A&) = delete;private:	int _a;};int main(){	A a1(10);	// 編譯失敗,因?yàn)樵擃悰]有拷貝構(gòu)造函數(shù)	//A a2(a1);	// 編譯失敗,因?yàn)樵擃悰]有賦值運(yùn)算符重載	A a3(20);	a3 = a2;	return 0;}

九、右值引用(熟悉)

1.右值引用概念

C++98中提出了引用的概念,引用即別名,引用變量與其引用實(shí)體公共同一塊內(nèi)存空間,而引用的底層是通過指針來實(shí)現(xiàn)的,因此使用引用,可以提高程序的可讀性。

#define _CRT_SECURE_NO_WARNINGS   1#includeusing namespace std;void Swap(int& left, int & right){	int tmp = left;	left = right;	right = tmp;}

為了提高程序運(yùn)行效率,C++11中引入了右值引用,右值引用也是別名,但其只能對(duì)右值引用。

int add(int a, int b){	return a + b;}int main(){	int a = 10;	int b = 20;	Swap(a, b);	const int&& ra = 10;	// 引用函數(shù)返回值,返回值是一個(gè)臨時(shí)變量,為右值	int&& rRet = add(10, 20);	return 0;}

為了與C++98中的引用進(jìn)行區(qū)分,C++11將該種方式稱之為右值引用。

2.左值與右值


左值與右值是C語(yǔ)言中的概念,但C標(biāo)準(zhǔn)并沒有給出嚴(yán)格的區(qū)分方式,一般認(rèn)為:可以放在=左邊的,或者能夠取地址的稱為左值,只能放在=右邊的,或者不能取地址的稱為右值,但是也不一定完全正確。

#define _CRT_SECURE_NO_WARNINGS   1#includeusing namespace std;int main(){	int x = 1;	int y = 2;	//左值引用的定義	int a = 0;	int &b = a;	//左值引用不能引用右值,但const左值引用可以	//int& e = 10;	//int& f = x + y;	const int& e = 10;	const int& f = x + y;	//右值引用的定義	int&& c = 10;	int&& d = x + y;	//右值引用不能引用左值,但是可以引用move后左值	//int&& m = a;	int&& m = move(a);		return 0;}
  • 因此關(guān)于左值與右值的區(qū)分不是很好區(qū)分,一般認(rèn)為:
  • 普通類型的變量,因?yàn)橛忻郑梢匀〉刂罚颊J(rèn)為是左值。
  • const修飾的常量,不可修改,只讀類型的,理論應(yīng)該按照右值對(duì)待,但因?yàn)槠淇梢匀〉刂?如果只是const類型常量的定義,編譯器不給其開辟空間,如果對(duì)該常量取地址時(shí),編譯器才為其開辟空間),C++11認(rèn)為其是左值。
  • 如果表達(dá)式的運(yùn)行結(jié)果是一個(gè)臨時(shí)變量或者對(duì)象,認(rèn)為是右值。
  • 如果表達(dá)式運(yùn)行結(jié)果或單個(gè)變量是一個(gè)引用則認(rèn)為是左值。
  • 總結(jié):
  • 不能簡(jiǎn)單地通過能否放在=左側(cè)右側(cè)或者取地址來判斷左值或者右值,要根據(jù)表達(dá)式結(jié)果或變量的性質(zhì)判斷,比如上述:c常量。
  • 能得到引用的表達(dá)式一定能夠作為引用,否則就用常引用。
  • C++11對(duì)右值進(jìn)行了嚴(yán)格的區(qū)分::
  • C語(yǔ)言中的純右值,比如:a+b, 100。
  • 將亡值。比如:表達(dá)式的中間結(jié)果、函數(shù)按照值的方式進(jìn)行返回。

3.引用與右值引用比較

在C++98中的普通引用與const引用在引用實(shí)體上的區(qū)別:

int main(){	// 普通類型引用只能引用左值,不能引用右值	int a = 10;	int& ra1 = a; // ra為a的別名	//int& ra2 = 10; // 編譯失敗,因?yàn)?0是右值	const int& ra3 = 10;	const int& ra4 = a;	return 0;}

注意: 普通引用只能引用左值,不能引用右值,const引用既可引用左值,也可引用右值。

C++11中右值引用:只能引用右值,一般情況不能直接引用左值。

int main(){	// 10純右值,本來只是一個(gè)符號(hào),沒有具體的空間,	// 右值引用變量r1在定義過程中,編譯器產(chǎn)生了一個(gè)臨時(shí)變量,r1實(shí)際引用的是臨時(shí)變量	int&& r1 = 10;	r1 = 100;	int a = 10;	int&& r2 = a; // 編譯失敗:右值引用不能引用左值	return 0;}

問題:既然C++98中的const類型引用左值和右值都可以引用,那為什么C++11還要復(fù)雜的提出右值引用呢?

4.值的形式返回對(duì)象的缺陷

如果一個(gè)類中涉及到資源管理,用戶必須顯式提供拷貝構(gòu)造、賦值運(yùn)算符重載以及析構(gòu)函數(shù),否則編譯器將會(huì)自動(dòng)生成一個(gè)默認(rèn)的,如果遇到拷貝對(duì)象或者對(duì)象之間相互賦值,就會(huì)出錯(cuò),比如:

#define _CRT_SECURE_NO_WARNINGS   1#include#includenamespace yyw{	class string	{		string(const char* str = "")		:_str(new char[strlen(str)+1])		{			strcpy(_str, str);		}		//s2(s1)		string(const string& s)			:_str(new char[strlen(s._str)+1])		{			strcpy(_str, s._str);		}		//s2=s1		string& operator=(const string& s)		{			if (this != &s)			{				char* _Pstr = new char[strlen(s._str) + 1];				strcpy(_Pstr, s._str);				delete[] _str;				_str = _Pstr;			}			return *this;		}		~string()		{			delete[]_str;			_str=nullptr;		}	private:		char* _str;	};}

上述代碼看起來沒有什么問題,但是有一個(gè)不太盡人意的地方:

在operator+中:strRet在按照值返回時(shí),必須創(chuàng)建一個(gè)臨時(shí)對(duì)象,臨時(shí)對(duì)象創(chuàng)建好之后,strRet就被銷毀了,最后使用返回的臨時(shí)對(duì)象構(gòu)造s3,s3構(gòu)造好之后,臨時(shí)對(duì)象就被銷毀了。仔細(xì)觀察會(huì)發(fā)現(xiàn):strRet、臨時(shí)對(duì)象、s3每個(gè)對(duì)象創(chuàng)建后,都有自己獨(dú)立的空間,而空間中存放內(nèi)容也都相同,相當(dāng)于創(chuàng)建了三個(gè)內(nèi)容完全相同的對(duì)象,對(duì)于空間是一種浪費(fèi),程序的效率也會(huì)降低,而且臨時(shí)對(duì)象確實(shí)作用不是很大,那能否對(duì)該種情況進(jìn)行優(yōu)化呢。

5.移動(dòng)語(yǔ)義

C++11提出了移動(dòng)語(yǔ)義概念,即:將一個(gè)對(duì)象中資源移動(dòng)到另一個(gè)對(duì)象中的方式,可以有效緩解該問題。

在C++11中如果需要實(shí)現(xiàn)移動(dòng)語(yǔ)義,必須使用右值引用。上述String類增加移動(dòng)構(gòu)造:

因?yàn)閟trRet對(duì)象的生命周期在創(chuàng)建好臨時(shí)對(duì)象后就結(jié)束了,即將亡值,C++11認(rèn)為其為右值,在用strRet構(gòu)造臨時(shí)對(duì)象時(shí),就會(huì)采用移動(dòng)構(gòu)造,即將strRet中資源轉(zhuǎn)移到臨時(shí)對(duì)象中。而臨時(shí)對(duì)象也是右值,因此在用臨時(shí)對(duì)象構(gòu)造s3時(shí),也采用移動(dòng)構(gòu)造,將臨時(shí)對(duì)象中資源轉(zhuǎn)移到s3中,整個(gè)過程,只需要?jiǎng)?chuàng)建一塊堆內(nèi)存即可,既省了空間,又大大提高程序運(yùn)行的效率。

注意:

  1. 移動(dòng)構(gòu)造函數(shù)的參數(shù)千萬(wàn)不能設(shè)置成const類型的右值引用,因?yàn)橘Y源無法轉(zhuǎn)移而導(dǎo)致移動(dòng)語(yǔ)義失效。
  2. 在C++11中,編譯器會(huì)為類默認(rèn)生成一個(gè)移動(dòng)構(gòu)造,該移動(dòng)構(gòu)造為淺拷貝,因此當(dāng)類中涉及到資源管理
    時(shí),用戶必須顯式定義自己的移動(dòng)構(gòu)造。

6.右值引用引用左值

按照語(yǔ)法,右值引用只能引用右值,但右值引用一定不能引用左值嗎?因?yàn)椋河行﹫?chǎng)景下,可能真的需要用右值去引用左值實(shí)現(xiàn)移動(dòng)語(yǔ)義。當(dāng)需要用右值引用引用一個(gè)左值時(shí),可以通過move函數(shù)將左值轉(zhuǎn)化為右值。C++11中,std::move()函數(shù)位于 頭文件中,該函數(shù)名字具有迷惑性,它并不搬移任何東西,唯一的功能就是將一個(gè)左值強(qiáng)制轉(zhuǎn)化為右值引用,然后實(shí)現(xiàn)移動(dòng)語(yǔ)義。

int main(){	String s1("hello world");	String s2(move(s1));	String s3(s2);	return 0;}

注意:以上代碼是move函數(shù)的經(jīng)典的誤用,因?yàn)閙ove將s1轉(zhuǎn)化為右值后,在實(shí)現(xiàn)s2的拷貝時(shí)就會(huì)使用移動(dòng)構(gòu)造,此時(shí)s1的資源就被轉(zhuǎn)移到s2中,s1就成為了無效的字符串。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/118811.html

相關(guān)文章

  • SpringBoot非官方教程 | 第二二篇: 創(chuàng)建含有多module的springboot工程

    這篇文章主要介紹如何在springboot中如何創(chuàng)建含有多個(gè)module的工程,栗子中含有兩個(gè) module,一個(gè)作為libarary. 工程,另外一個(gè)是主工程,調(diào)用libary .其中l(wèi)ibary jar有一個(gè)服務(wù),main工程調(diào)用這個(gè)服務(wù)。 創(chuàng)建根工程 創(chuàng)建一個(gè)maven 工程,其pom文件為: 4.0.0 com.forezp springboot-multi-...

    Scott 評(píng)論0 收藏0
  • 機(jī)器視覺、模式識(shí)別庫(kù)匯總

    摘要:十開放模式識(shí)別項(xiàng)目開放模式識(shí)別項(xiàng)目,致力于開發(fā)出一套包含圖像處理計(jì)算機(jī)視覺自然語(yǔ)言處理模式識(shí)別機(jī)器學(xué)習(xí)和相關(guān)領(lǐng)域算法的函數(shù)庫(kù)。 一、開源生物特征識(shí)別庫(kù) OpenBROpenBR 是一個(gè)用來從照片中識(shí)別人臉的工具。還支持推算性別與年齡。使用方法:$ br -algorithm FaceRecognition -compare me.jpg you.jpg二、計(jì)算機(jī)視覺庫(kù) OpenCVOpenC...

    habren 評(píng)論0 收藏0
  • 全國(guó)計(jì)算機(jī)等級(jí)考試二級(jí)Python(2021年9月)備考筆記 第十二

    摘要:本題目的考察點(diǎn)在于函數(shù)的格式輸出規(guī)則。方法改變隨機(jī)數(shù)生成器的種子,可以在調(diào)用其他隨機(jī)模塊函數(shù)之前調(diào)用此函數(shù)。參數(shù)改變隨機(jī)數(shù)生成器的種子。返回一個(gè)至區(qū)間包含和的整數(shù)。 ...

    Codeing_ls 評(píng)論0 收藏0
  • 【萬(wàn)人千題】大學(xué)生算法社區(qū)火爆開啟,每日打卡學(xué)習(xí),誠(chéng)邀妳的加入

    摘要:三結(jié)對(duì)編程排位賽四個(gè)人為一組,由隊(duì)長(zhǎng)帶隊(duì)刷題,每周根據(jù)這周四個(gè)人的刷題總數(shù)進(jìn)行隊(duì)伍間排名。萬(wàn)人千題結(jié)對(duì)編程排位賽如果想?yún)⒓拥牡诙诘耐瑢W(xué),可以先聯(lián)系作者加群,看看第一期的同袍是如何奮斗的。 ...

    morgan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<