国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

C++11 新功能

這篇具有很好參考價(jià)值的文章主要介紹了C++11 新功能。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

C++11

在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ù),語言的核心部分則沒

有改動(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中孕育出的一種新語

言。相比較而言,C++11能更好地用于系統(tǒng)開發(fā)和庫(kù)開發(fā)、語法更加泛華和簡(jiǎn)單化、更加穩(wěn)定和安全,不僅功能更強(qiáng)大,而且能提升程序員的開發(fā)效率。

一 列表初始化

在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<int> v{1,2,3,4,5};就無法通過編譯,導(dǎo)致每次定義vector時(shí),都需要先把vector定義出來,然后使用循環(huán)對(duì)其賦初始值,非常不方便。C++11擴(kuò)大了用大括號(hào)括起的列表(初始化列表)的使用范圍,使其可用于所有的內(nèi)置類型和用戶自定義的類型,使用初始化列表時(shí),可添加等號(hào)(=)也可不添加。列表初始化可以在{}之前使用等號(hào),其效果與不使用=沒有什么區(qū)別。

單個(gè)對(duì)象的多參數(shù)列表初始化
#include<iostream>
#include<vector>
#include<map>
#include<string>
using namespace std;
struct B
{
	int _x;
	int _y;
};
class Point
{
public:
	Point(int x = 0, int y = 0)
		:_x(x)
		, _y(y)
	{}
private:
	int _x;
	int _y;
};
class A 
{
public:
	//內(nèi)含單參數(shù)的構(gòu)造函數(shù)
	A(int a)
		:_a(a)
	{}
	/*explicit A(int a)
		:_a(a)
	{}*/
private:
	int _a;
};
int main()
{
	//自定義類型
	// 當(dāng)添加explicit之后就不讓轉(zhuǎn)換了
	//單參數(shù)構(gòu)造函數(shù),支持隱士類型轉(zhuǎn)換
	A aa(1);
	A aa2 = 2;//隱士類型轉(zhuǎn)換int->A
	//同理
	string s1("hello");
	string s2="world";//const char* ->string
	vector<string>v;
	v.push_back("world");

	//C++11-多參數(shù),支持隱士類型轉(zhuǎn)換
	Point p{ 1,2 };
	B b{1,2};//兼容C語言
	int* ptr1 = new int[5] {1, 2, 3, 4, 5};
	Point* ptr2 = new Point[2]{ {1,2},{3,4} };
	//內(nèi)置類型
	int x1 = { 10 };
	int x2{ 10 };
	int x3{ 1 + 2 };
	int x4 = { 1 + 2 };
	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};
	vector<int>v{ 1,2,3,4,5 };
	map<int, int> m{ {1,1},{2,2},{3,3} };
	return 0;
}
多個(gè)對(duì)象的列表初始化

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

編譯器自己識(shí)別{}為initializer_list類型進(jìn)行轉(zhuǎn)化。

比如vector:

C++11 新功能

#include <initializer_list>
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;
};
int main()
{
	//自己實(shí)現(xiàn)的
	Vector<int> vv = { 1,2,3,4,5 };
	Vector<int> vv2 = vv;
	//多個(gè)對(duì)象支持列表初始化
	vector<int>v1 = {1,2,3,4,5};
	list<int> l1 = {1,2,3,4,5};
	pair<string, string>kv("left","左邊");
	map<string, string>dict = { {"insert","插入"},kv};
	initializer_list<int> ilt = {1,2,32,4,5};
}
自己編寫list使用initializer_list支持多對(duì)象的列表初始化

注意:如果使用迭代器時(shí)報(bào)錯(cuò),前面加上typename initializer_list<T>:;iterator ,這是在類模板中再去找他的內(nèi)嵌類型,未實(shí)例化之前可能取不到。告訴編譯器類模板實(shí)例化了之后再去調(diào)用類里面的迭代器。

C++11 新功能

二 stl中的一些變化

  • 新增一些容器
  • 已有容器增加一些好用或者提高效率的接口。比如列表初始化initializer_list,右值引用相關(guān)接口提高效率。移動(dòng)構(gòu)造,移動(dòng)賦值。cbegin(),cend(),emplace_back(),emplace().
array

定長(zhǎng)數(shù)組,相比于變長(zhǎng)數(shù)組vector。

優(yōu)點(diǎn):支持迭代器,更好的兼容STL容器。對(duì)于越界的檢查。

std::array
template < class T, size_t N > class array;

int main()
{
	array<int, 10>a;
	int a1[10];//數(shù)組

	a1[14] = 0;//抽查行為,*(a+14)=0,越界可能不檢查
	a[14] = 0;//a.operator[](14)=0,對(duì)于函數(shù)的調(diào)用,肯定檢查
	return 0;
}
forword_list

forward_list,單鏈表,支持頭插頭刪(push_front() pop_front()),支持在節(jié)點(diǎn)后面插入刪除,不支持尾插尾刪和在節(jié)點(diǎn)之前的操作

unordered_map unordered_set

三 右值引用和移動(dòng)語義

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

左值與右值是C語言中的概念,但C標(biāo)準(zhǔn)并沒有給出嚴(yán)格的區(qū)分方式,一般認(rèn)為:

  • 可以放在=左邊的,變量或者解引用的指針,我們可以獲取他的地址+可以對(duì)他賦值,稱為左值。const修飾的左值可以取地址,但是不可以賦值。

  • 只能放在=右邊的,或者不能取地址的稱為右值。表示數(shù)據(jù)的表達(dá)式如:字面常量,表達(dá)式返回值,傳值返回函數(shù)的返回值,臨時(shí)對(duì)象也是右值。

左值引用& vs 右值引用&&
const int b=10;//常量,函數(shù)返回值等不能取地址的都是右值
int main()
{
//可以取地址對(duì)象就是左值
	const int b = 10;//b是左值,可以取地址不能賦值
    const int& r3=b; //左值引用
//右值
	double x = 1.1, y = 2.2;
	x + y;
	double &&r4=fmin(x,y);
    
//右值引用就是右值的別名
	int&& rr1 = 10;
    
//左值引用不能直接引用右值,得加上const
	const int& r1 = x + y;
	const int& r2 = 10;
	const int& r3 = fmin(x,y);
    const int& p1 = (10+20);
    //void push_back(const T& x)這樣傳參,對(duì)面左值引用和右值引用均可傳過去
    
//右值引用不能直接引用左值,但是可以右值引用move以后的左值
	int d = 10;
	int* p = &d;
	int*&& rr1 = move(p);
    int n = 10;
	int&& p2 = move(n);
    const int p = 20;
	const int&& rr2 = move(p2);
//給右值取別名之后會(huì)改變存儲(chǔ)位置,另開辟個(gè)空間存儲(chǔ)右值,別名就是個(gè)左值了
    cout<<&p2<<endl;
	return 0;
}
右值引用的應(yīng)用
  • 為了彌補(bǔ)左值引用的不足。

左值引用:傳值傳參會(huì)調(diào)用拷貝構(gòu)造函數(shù),作為參數(shù)基本完美解決問題;作為返回值以下問題就不完美只能解決部分問題,所以可用右值引用優(yōu)化。

string& operator+=(char ch)
{
	push_back(ch);
	return *this;//處理作用域還在,就很完美
}
string operator+(char ch)
{
	string tmp(*this);
	push_back(ch);
	return tmp;//出了作用域就會(huì)被銷毀,傳值返回會(huì)多一次拷貝構(gòu)造,然后再析構(gòu),不完美。
    //所以只能用傳值返回是右值
}
  • 右值引用如何解決operator+的拷貝構(gòu)造問題呢?

提供一個(gè)移動(dòng)構(gòu)造,是右值只會(huì)去移動(dòng)構(gòu)造中,走最匹配的那個(gè)函數(shù)。

注意:C++11中將右值分為:自定義類型叫將亡值,或者純右值。

移動(dòng)構(gòu)造
//拷貝構(gòu)造
string(const string &s)//左值
	:_str(nullptr)
	,_size(0)
	,_capacity(0)
{
	string tmp(s._str);
	swap(tmp);
}

//移動(dòng)構(gòu)造,一種資源轉(zhuǎn)移,避免了資源的些許浪費(fèi),少一層拷貝
string(string &&s)//右值(臨時(shí)對(duì)象也是一種右值)
	:str(nullptr)
{
	this->swap(s);
    return *this;
}

int main()
{
	string s("hello world");
	string s1 = s;
	string s2 = move(s);//將s左值的屬性修改為右值屬性,賦予了別人將自己的資源拿走的權(quán)利
	//單純的move并不會(huì)對(duì)于s造成影響,當(dāng)傳給別人時(shí)就會(huì)有影響。
	return 0;
}
//右值引用理解場(chǎng)景2
string to_string(int value)
{
	string str;
	while(value)
	{
		int val=value%10;
		str+=('0'+val);
		value/=10;
	}
	reverse(str.begin(),str.end());
	return str;
}
int main()
{
	string ret=to_string(1234);
}

? 首先,如果編譯器不優(yōu)化,str拷貝構(gòu)造臨時(shí)對(duì)象,臨時(shí)對(duì)象(在main函數(shù)的棧幀中)作為to_string的返回值構(gòu)造ret。優(yōu)化之后,在to_string結(jié)束之前,用str構(gòu)造ret,從兩次拷貝構(gòu)造優(yōu)化為只有一次拷貝構(gòu)造。

C++11 新功能

  • 什么情況可優(yōu)化?

    當(dāng)用臨時(shí)對(duì)象去構(gòu)造ret時(shí),也就是有ret接收時(shí)會(huì)進(jìn)行優(yōu)化。當(dāng)沒有ret時(shí),因?yàn)閟tr在to_string函數(shù)結(jié)束之后要被銷毀,必須得有一個(gè)臨時(shí)對(duì)象作為返回值返回,還沒人接收時(shí)就無法優(yōu)化。

    C++11 新功能

? 如果有了移動(dòng)構(gòu)造之后,

  • 如果不考慮優(yōu)化的存在,原來的兩次拷貝構(gòu)造變成一次拷貝構(gòu)造,一次移動(dòng)構(gòu)造,因?yàn)閟tr是左值調(diào)用一次拷貝構(gòu)造產(chǎn)生臨時(shí)變量,此時(shí)產(chǎn)生的拷貝的臨時(shí)對(duì)象被認(rèn)為是右值,調(diào)用移動(dòng)構(gòu)造。

  • 優(yōu)化之后,就變成了一次移動(dòng)構(gòu)造,魯莽地直接將str認(rèn)為是右值,

    • 如果有ret接收,直接移動(dòng)構(gòu)造交給ret,完成一次資源轉(zhuǎn)移。

    • 如果沒有ret接收,之前直接將ret視為右值的存在在to_string()函數(shù)銷毀時(shí)作為函數(shù)返回值返回即可。

  • 資源轉(zhuǎn)移:有ret接收,就資源轉(zhuǎn)移給ret,如果沒ret接收,就資源轉(zhuǎn)移給一個(gè)函數(shù)必有的函數(shù)返回值。

C++11 新功能

  • 移動(dòng)構(gòu)造提升效率一個(gè)例子:

C++11 新功能

使得C++11 效率更高,當(dāng)然,如果vv是靜態(tài)或者是全局的,出了作用域還在,直接用左值返回就OK了。

移動(dòng)賦值
//移動(dòng)賦值
string& operator=(string&& s)
{
	cout<<"轉(zhuǎn)移資源"<<endl;
	swap(s);
	return *this;
}
//正常深拷貝賦值
string & operator=(const string &s)
{
	cout<<"深拷貝"<<endl;
	string tmp(s);
	swap(tmp);
	return *this;
}
int main()
{
    yuanwei::string s1("hello");
    yuanwei::string s2("world");
    s2=move(s1);//此時(shí)是右值,走匹配的右值引用,走移動(dòng)賦值函數(shù)實(shí)現(xiàn)資源轉(zhuǎn)移
    //避免移動(dòng)構(gòu)造,先有一個(gè)對(duì)象
	string ret;
	ret=to_string(12345);
}

如果有移動(dòng)賦值時(shí),將str作為右值直接進(jìn)行移動(dòng)構(gòu)造,資源轉(zhuǎn)移給臨時(shí)對(duì)象,再用臨時(shí)對(duì)象移動(dòng)賦值給ret,兩次資源轉(zhuǎn)移。將臨時(shí)對(duì)象這個(gè)已經(jīng)存在的對(duì)象交給ret這個(gè)已經(jīng)存在的對(duì)象。

如果沒有移動(dòng)賦值函數(shù),to_string()的str被識(shí)別為右值移動(dòng)構(gòu)造資源轉(zhuǎn)移給臨時(shí)對(duì)象,臨時(shí)對(duì)象賦值走一遍深拷貝交給已經(jīng)存在的ret。

  • 容器的插入接口也提供了一個(gè)右值引用的版本
//List C++11
void push_back (const value_type& val);
void push_back (value_type&& val);//新增

int main()
{
	//string也有右值引用
	list<string> lt;
	string s("11111111");
	lt.push_back(s);//傳參是左值,是深拷貝構(gòu)造
	cout<<endl;
	
    lt.push_back("22222222");//右值引用,移動(dòng)構(gòu)造,資源轉(zhuǎn)移
    cout<<endl;

    lt.push_back(to_string(333333));//to_string 一次str移動(dòng)構(gòu)造給臨時(shí)對(duì)象返回
                                    //push_back走右值引用版本移動(dòng)賦值,定位new節(jié)點(diǎn)上,到lt中。
    cout<<endl;
}

C++11 新功能

完美轉(zhuǎn)發(fā)

模板中的&&不代表右值引用,而是萬能引用,其既能接收左值又能接收右值。
模板的萬能引用只是提供了能夠接收同時(shí)接收左值引用和右值引用的能力,
但是引用類型的唯一作用就是限制了接收的類型,后續(xù)使用中都退化成了左值,
我們希望能夠在傳遞過程中保持它的左值或者右值的屬性, 就需要用我們下面學(xué)習(xí)的完美轉(zhuǎn)發(fā)

  • 退化的例子,如圖所示:

C++11 新功能

C++11 新功能

使用完美轉(zhuǎn)發(fā)之后:

C++11 新功能

  • 只要右值引用,再傳遞其他函數(shù)調(diào)用,要保持右值屬性,必須用完美轉(zhuǎn)發(fā),然后走的yuanwei::string的移動(dòng)賦值,資源轉(zhuǎn)移。
template<class T>
struct ListNode
{
	ListNode* _next = nullptr;
	ListNode* _prev = nullptr;
	T _data;
};
template<class T>
class List
{
	typedef ListNode<T> Node;
public:
	List()
	{
		_head = new Node;
		_head->_next = _head;
		_head->_prev = _head;
	}

	void PushBack(T&& x)
	{
		// 只要右值引用,再傳遞其他函數(shù)調(diào)用,要保持右值屬性,必須用完美轉(zhuǎn)發(fā),然后走的yuanwei::string的移動(dòng)賦值,資源轉(zhuǎn)移
		//Insert(_head, x);//這個(gè)x退化為左值,就會(huì)去調(diào)用yuanwei::string中的深拷貝
		Insert(_head, std::forward<T>(x));
	}

	void PushFront(T&& x)
	{
		//Insert(_head->_next, x);
		Insert(_head->_next, std::forward<T>(x));
	}

	void Insert(Node* pos, T&& x)
	{
		Node* prev = pos->_prev;

		//Node* newnode = new Node;
		//newnode->_data = std::forward<T>(x); // 關(guān)鍵位置

		Node* newnode = (Node*)malloc(sizeof(Node));
		//new(&newnode->_data)T(x);
		//定位new調(diào)用從拷貝構(gòu)造->移動(dòng)構(gòu)造
		new(&newnode->_data)T(std::forward<T>(x));
   //new是開空間+調(diào)用構(gòu)造函數(shù)初始化
   //stl中的容器的空間是從內(nèi)存池來的,和malloc效果一樣,只開空間不初始化也就不會(huì)調(diào)用構(gòu)造函數(shù),對(duì)已經(jīng)存在的空間初始化,需要用定位new初始化空間,就像這個(gè)一樣。
        
		// prev newnode pos
		prev->_next = newnode;
		newnode->_prev = prev;
		newnode->_next = pos;
		pos->_prev = newnode;
	}

	void Insert(Node* pos, const T& x)
	{
		Node* prev = pos->_prev;
		Node* newnode = new Node;
		newnode->_data = x; // 關(guān)鍵位置

		// prev newnode pos
		prev->_next = newnode;
		newnode->_prev = prev;
		newnode->_next = pos;
		pos->_prev = newnode;
	}
private:
	Node* _head;
};

int main()
{
	List<yuanwei::string> lt;
	lt.PushBack("1111");
	//lt.PushFront("2222");

	return 0;
}
emplace_back()

push_back VS emplace_back

//二者相比,右值版本不會(huì)更加高效,差不多
//左值版本 emplace 會(huì)更高效,因?yàn)樗淮嬖谏羁截惖膯栴}
int main()
{
	std::list<pair<int, char>>mylist;
	//兩次資源轉(zhuǎn)移,先構(gòu)造右值,再移動(dòng)構(gòu)造
	mylist.push_back(make_pair(1,'A'));//一個(gè)類型參數(shù)
	mylist.push_back({1,'a'});//pair支持{}初始化
    
	//兩次直接構(gòu)造
	mylist.emplace_back(make_pair(1,'a'));//整體作為單參數(shù)對(duì)象
	mylist.emplace_back(1,'a');//多參數(shù)傳值也支持
	return 0;
}

emplace_back()是直接構(gòu)造,pushback()是先構(gòu)造對(duì)象,然后再進(jìn)行資源轉(zhuǎn)移.

C++11 新功能

類的新功能
  • 原來的默認(rèn)構(gòu)造函數(shù)有6個(gè),重要的有4個(gè):析構(gòu)函數(shù),構(gòu)造函數(shù),拷貝構(gòu)造函數(shù),拷貝賦值函數(shù).

    • 默認(rèn)生成的構(gòu)造函數(shù)不寫的話,會(huì)自動(dòng)生成并在初始化列表階段調(diào)用自定義成員的構(gòu)造函數(shù).
  • 新的是移動(dòng)構(gòu)造函數(shù),移動(dòng)賦值函數(shù)。這倆的使用規(guī)則是相同的,下面只介紹一個(gè):

如果在類中,你沒有實(shí)現(xiàn)移動(dòng)構(gòu)造函數(shù),并且你沒有實(shí)現(xiàn)你的析構(gòu)函數(shù)拷貝構(gòu)造函數(shù),拷貝賦值函數(shù)其中一個(gè),那么會(huì)給你生成默認(rèn)移動(dòng)構(gòu)造函數(shù);他對(duì)于內(nèi)置類型是采用值拷貝的方式,對(duì)于自定義類型,當(dāng)自定義類型本身是提供移動(dòng)構(gòu)造函數(shù)的話,就調(diào)用。如果沒有,就去調(diào)用拷貝構(gòu)造函數(shù)。
同理移動(dòng)賦值函數(shù)。

C++11 新功能

類成員初始化

類內(nèi)聲明內(nèi)置類型的時(shí)候給個(gè)缺省值

四 可調(diào)用對(duì)象類型

  • C-函數(shù)指針void(*p)();
  • C++98-仿函數(shù)/函數(shù)對(duì)象
  • C++11-lambda表達(dá)式/匿名函數(shù)
//仿函數(shù)
struct Goods
  {
  string _name;  // 名字
  double _price; // 價(jià)格
  int _evaluate; // 評(píng)價(jià)

  Goods(const char* str, double price, int evaluate)
  	:_name(str)
  	, _price(price)
  	, _evaluate(evaluate)
  {}
  };

struct ComparePriceLess
{
	bool operator()(const Goods& gl, const Goods& gr)
	{
		return gl._price < gr._price;
	}
};

struct ComparePriceGreater
{
	bool operator()(const Goods& gl, const Goods& gr)
	{
		return gl._price > gr._price;
	}
};

int main()
{
	//仿函數(shù)
	vector<Goods> v = { { "蘋果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2, 3 }, { "菠蘿", 1.5, 4 } };
	sort(v.begin(), v.end(), ComparePriceLess());
	sort(v.begin(), v.end(), ComparePriceGreater());
    
	//C++11 lambda表達(dá)式
	auto priceLess = [](const Goods& g1, const Goods& g2){return g1._price < g2._price; };
	sort(v.begin(), v.end(), priceLess);

	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._price < g2._price; });
	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._price > g2._price; });
	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._evaluate < g2._evaluate; });
	sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2){return g1._evaluate > g2._evaluate; });
    return 0;
}

lambda表達(dá)式

lambda表達(dá)式書寫格式:[capture-list] (parameters) mutable -> return-type { statement }

lambda表達(dá)式各部分說明

[capture-list] : 捕捉列表,該列表總是出現(xiàn)在lambda函數(shù)的開始位置,編譯器根據(jù)[]來判斷接下來的代碼是否為lambda函數(shù)**,**捕捉列表能夠捕捉上下文中的變量供lambda函數(shù)使用。所以不能省略。

(parameters):參數(shù)列表。與普通函數(shù)的參數(shù)列表一致,如果不需要參數(shù)傳遞,則可以連同()一起省略

mutable:默認(rèn)情況下,lambda函數(shù)總是一個(gè)const函數(shù),mutable可以取消其常量性。使用該修飾符時(shí),參數(shù)列表不可省略(即使參數(shù)為空)。

->returntype:返回值類型。用追蹤返回類型形式聲明函數(shù)的返回值類型,沒有返回值時(shí)此部分可省略。返回值類型明確情況下,也可省略,由編譯器對(duì)返回類型進(jìn)行推導(dǎo)。

{statement}:函數(shù)體。在該函數(shù)體內(nèi),除了可以使用其參數(shù)外,還可以使用所有捕獲到的變量。

注意: 在lambda函數(shù)定義中,參數(shù)列表和返回值類型都是可選部分,而捕捉列表和函數(shù)體可以為空。因此C++11中最簡(jiǎn)單的lambda函數(shù)為:[]{}; 該lambda函數(shù)不能做任何事情。

int main()
{
	//lambda實(shí)現(xiàn)兩個(gè)數(shù)相加的功能
	auto add1=[](int a,int b) ->int {return a + b; };
    //調(diào)用方式
    cout<<add1(1,2)<<endl;
    auto add3=add1;
    decltype(add1) add3=add1;
//返回值可以省略
	auto add2 = [](int a,int b){return a + b; };
//沒有參數(shù)可以省略參數(shù)列表沒有返回值
	auto func1 = [] { cout << "hello" << endl; };
//捕捉列表不能省略[]
	auto swap1 =  [](int& a,int& b){
		int c = a;
		a = b;
		b = c; };
    swap1(3,4);
    
    int a = 3, b = 4; 
    auto fun1 = [&](int c) {b = a + c; };
    //auto fun1 = [&a,&b](int c) {b = a + c; };//傳引用捕捉才能改變值
    fun1(10);
    cout << a << " " << b << endl;

    int a = 0;
    int b = 1;
//傳值捕捉,調(diào)用之后并不能改變ab的值,只是一份拷貝交換了.
  //加上mutable lambda函數(shù)總是一個(gè)const函數(shù),mutable可以取消其常量性。使用該修飾符,參數(shù)列表不能省略。
    //但是還是不能交換成功
    auto swap2 = [a, b]()mutable {
        int c = a;
        a = b;
        b = c;
       };
	swap2();//捕捉就不需要傳參數(shù)了
    
//傳引用捕捉
    auto swap3 = [&a, &b]() {
        int c = a; 
        a = b;
        b = c;
    };
    swap3();
}
捕捉聲明:

捕捉列表描述了上下文中那些數(shù)據(jù)可以被lambda使用,以及使用的方式傳值還是傳引用。

[var]:表示值傳遞方式捕捉變量var
[=]:表示值傳遞方式捕獲所有父作用域中的變量(包括this),如果指定某一個(gè)變量進(jìn)行值傳遞,[a,b]指明出來
[&var]:表示引用傳遞指定的捕捉變量var
[&]:表示引用傳遞捕捉所有父作用域中的變量(包括this)
[this]:表示值傳遞方式捕捉當(dāng)前的this指針

注意事項(xiàng):

a. 父作用域指包含lambda函數(shù)的語句塊

b. 語法上捕捉列表可由多個(gè)捕捉項(xiàng)組成,并以逗號(hào)分割。比如:[=, &a, &b]:以引用傳遞的方式捕捉變量a和b,值傳遞方式捕捉其他所有變量 [&,a, this]:值傳遞方式捕捉變量a和this,引用方式捕捉其他變量

c. 捕捉列表不允許變量重復(fù)傳遞,否則就會(huì)導(dǎo)致編譯錯(cuò)誤。 比如:[=, a]:=已經(jīng)以值傳遞方式捕捉了所有變量,捕捉a重復(fù)。

d. 在塊作用域以外的lambda函數(shù)捕捉列表必須為空。在全局中無法捕捉變量。

e. 在塊作用域中的lambda函數(shù)僅能捕捉父作用域中局部變量,捕捉任何非此作用域或者非局部變量都會(huì)導(dǎo)致編譯報(bào)錯(cuò)。

f. lambda表達(dá)式之間不能相互賦值,即使看起來類型相同

void (*PF)();
int main()
{
	auto f1 = [] {cout << "hello world" << endl; };
	auto f2 = [] {cout << "hello world" << endl; };
	//f1 = f2; // 編譯失敗--->提示找不到operator=()
	
	// 允許使用一個(gè)lambda表達(dá)式拷貝構(gòu)造一個(gè)新的副本
	auto f3(f2);
	f3();
	// 可以將lambda表達(dá)式賦值給相同類型的函數(shù)指針
	PF = f2;
	PF();
	return 0;
}
函數(shù)對(duì)象(仿函數(shù))與lambda表達(dá)式

函數(shù)對(duì)象,又稱為仿函數(shù),即可以像函數(shù)一樣使用的對(duì)象,就是在類中重載了operator()運(yùn)算符的類對(duì)象。

lambda表達(dá)式,底層原理其實(shí)是被處理成一個(gè)lambda_uuid的一個(gè)仿函數(shù)類。

class Rate
{
public:
	Rate(double rate) : _rate(rate)
	{}
	double operator()(double money, int year)
	{
		return money * _rate * year;
	}
private:
	double _rate;
};
int main()
{
	// 函數(shù)對(duì)象
	double rate = 0.49;
	Rate r1(rate);
	r1(10000, 2);
	// lamber
	auto r2 = [=](double monty, int year)->double {return monty * rate * year; };
	r2(10000, 2);
	//cout << typeid(r2).name() <<endl;
	return 0;
}

C++11 新功能

從使用方式上來看,函數(shù)對(duì)象與lambda表達(dá)式完全一樣。函數(shù)對(duì)象將rate作為其成員變量,在定義對(duì)象時(shí)給出初始值即可,lambda表達(dá)式通過捕獲列表可以直接將該變量捕獲到。

實(shí)際在底層編譯器對(duì)于lambda表達(dá)式的處理方式,完全就是按照函數(shù)對(duì)象的方式處理的,即:如果定義了一個(gè)lambda表達(dá)式,編譯器會(huì)**自動(dòng)生成一個(gè)類,在該類中重載了operator()。**仿函數(shù)對(duì)象去調(diào)用operator()。

五 關(guān)鍵字

auto

在定義變量時(shí),必須先給出變量的實(shí)際類型,編譯器才允許定義,但有些情況下可能不知道需要實(shí)際類型怎

么給,或者類型寫起來特別復(fù)雜。C++11中,可以使用auto來根據(jù)變量初始化表達(dá)式類型推導(dǎo)變量的實(shí)際類型,可以給程序的書寫提供許多方便。將程序中c與it的類型換成auto,程序可以通過編譯,而且更加簡(jiǎn)潔

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

C++98中確實(shí)已經(jīng)支持RTTI:typeid只能查看類型不能用其結(jié)果類定義類型。dynamic_cast只能應(yīng)用于含有虛函數(shù)的繼承體系運(yùn)行時(shí)類型識(shí)別的缺陷是降低程序運(yùn)行的效率。

int func(int a)
{
	return a;
}
int main()
{
	int a = 10;
	int b = 20;

	// 用decltype推演a+b的實(shí)際類型,作為定義c的類型
	decltype(a + b) c;
	//C++98 const int ->int 會(huì)存在區(qū)別,decltype就不會(huì)存在
	cout << typeid(c).name() << endl;

	//聲明函數(shù)指針類型
	int(*pfunc1)(int) = func;
	auto pfunc2 = func;
	decltype(pfunc2) pfunc3 = func;//和auto配合使用
	decltype(&func) pfunc4 = func;
	map<string, string> dict = { {"left","左邊"}};
	auto it = dict.begin();
	//decltype的使用場(chǎng)景:要頂一個(gè)auto推導(dǎo)對(duì)象的拷貝
	decltype(it) copyIt1 = it;
	auto copyIt2 = it;
	//vector<auto>無法通過編譯
	vector<decltype(it)> v;
	v.push_back(it);
}
final-不讓繼承
override-檢查能否被重寫
default

? 在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讓程序員可以控制是否需要編譯器生成。顯示缺省函數(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;
}
delete

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

比如:?jiǎn)卫J较拢?guī)定聲明的對(duì)象只能有一個(gè),這個(gè)對(duì)象是不允許被拷貝構(gòu)造其他的對(duì)象的,C++98 的方法一是,讓拷貝構(gòu)造函數(shù)私有化,在類的外面就調(diào)用不到了,但是呢,在類的里面中的某個(gè)函數(shù)還是可以調(diào)用的,同時(shí)造成默認(rèn)構(gòu)造函數(shù)就無法生成了。如果類的里面也不讓調(diào)用時(shí),也就是方法二:在私有中,只聲明但是不實(shí)現(xiàn)來防止拷貝。注意:如果不設(shè)置成私有的話,別人可以在類的外面實(shí)現(xiàn)拷貝構(gòu)造函數(shù),從而控制你提供的類做出修改。

C++11 就直接提供了關(guān)鍵字delete,在拷貝構(gòu)造函數(shù)的后面加上:delete 函數(shù)就變成了已刪除函數(shù),也無論私有與否了。

避免刪除函數(shù)和explicit一起使(explicit是防止函數(shù)進(jìn)行隱式類型轉(zhuǎn)換)

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;
}

六 模板的可變參數(shù)

  • printf
int printf ( const char * format, ... );//可變參數(shù)
  • 解析打印參數(shù)包中的類型和值

C++11 新功能

//遞歸終止函數(shù)
template<class T>
void ShowList(const T& t)
{
	cout << t <<endl;
}

template<class T,class ...Args>//Args模板參數(shù)包
void ShowList(T val, Args ... args)//args形參參數(shù)包
{
    cout << typeid(val).name() << ":" << val << endl;
    ShowList(args...);//遞歸依次到達(dá)下一個(gè)參數(shù)
}
int main()
{
    ShowList(1);
    ShowList(1, 'A');
    ShowList(1,'A',string("sort"));

return 0;
}
逗號(hào)表達(dá)式展開參數(shù)包

C++11 新功能文章來源地址http://www.zghlxwxcb.cn/news/detail-411304.html

//參數(shù)包,傳一個(gè)或者多個(gè)
template<class T>
void PrintArg(T val)
{
	T copy(val);
	cout << typeid(T).name() << ":" << val << endl;
}
template<class ...Args>
void ShowList(Args... args)
{
    //{}列表初始化,開多大空間取決于可變參數(shù)個(gè)數(shù),依次取出參數(shù)包
    //但是函數(shù)沒有返回值,創(chuàng)建數(shù)組需要元素有返回值,所以用逗號(hào)表達(dá)式,帶個(gè)0
	int arr[] = {(PrintArg(args),0)...};
	//逗號(hào)表達(dá)式,0是返回值。
	cout << endl;
}
//帶返回值,不用逗號(hào)表達(dá)式
template<class T>
int PrintArg(T val)
{
	T copy(val);
	cout << typeid(T).name() << ":" << val << endl;
	return 0;
}
template<class ...Args>
void ShowList(Args... args)
{
	int arr[] = { PrintArg(args)... };
	//0是返回值
	cout << endl;
}
int main()
{
	ShowList(1);
	ShowList(1, 'A');
	ShowList(1,'A',string("sort"));

	return 0;
}
endl;
    ShowList(args...);//遞歸依次到達(dá)下一個(gè)參數(shù)
}
int main()
{
    ShowList(1);
    ShowList(1, 'A');
    ShowList(1,'A',string("sort"));

return 0;
}

到了這里,關(guān)于C++11 新功能的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【C++】C++11類的新功能

    【C++】C++11類的新功能

    ?? 樊梓慕: 個(gè)人主頁 ??? 個(gè)人專欄: 《C語言》 《數(shù)據(jù)結(jié)構(gòu)》 《藍(lán)橋杯試題》 《LeetCode刷題筆記》 《實(shí)訓(xùn)項(xiàng)目》 《C++》 《Linux》 《算法》 ?? 每一個(gè)不曾起舞的日子,都是對(duì)生命的辜負(fù) 目錄 前言 默認(rèn)成員函數(shù) 類成員變量初始化 強(qiáng)制生成默認(rèn)函數(shù)的default 禁止生

    2024年04月17日
    瀏覽(37)
  • Copilot的11個(gè)新功能,你不能錯(cuò)過!

    Copilot的11個(gè)新功能,你不能錯(cuò)過!

    我的新書 《Android App開發(fā)入門與實(shí)戰(zhàn)》 已于2020年8月由人民郵電出版社出版,歡迎購(gòu)買。點(diǎn)擊進(jìn)入詳情 微軟發(fā)布了Copilot,這個(gè)東西真是太瘋狂了。 如果你不使用它,你就會(huì)在2023年落后了。 將Word文檔轉(zhuǎn)換為演示文稿。 從文件中快速創(chuàng)建演示文稿。 通過關(guān)鍵幻燈片總結(jié)冗長(zhǎng)

    2024年02月04日
    瀏覽(52)
  • 官宣Windows11十月的Moment 1來了,新功能!附官方ISO鏡像(簡(jiǎn)/繁/英)

    官宣Windows11十月的Moment 1來了,新功能!附官方ISO鏡像(簡(jiǎn)/繁/英)

    一個(gè)月前(2022年9月)微軟正式發(fā)布了Windows 11的年度大更新——22H2版本(Build 22621.382),過了沒幾天當(dāng)月又推出了Build 22621.525的ISO鏡像。給人一種特別操之過急的感覺~ 前天微軟又向MVS訂閱用戶推送了10月份的累積更新的ISO鏡像,系統(tǒng)版本號(hào)Build 22621.674。Windows11也是維持著每

    2024年02月06日
    瀏覽(23)
  • 【C++】C++11-類的新功能&default&delete&final&override關(guān)鍵字

    一個(gè)類有多少個(gè)默認(rèn)成員函數(shù)? c++98:6個(gè) C++11:8個(gè) 在C++98中,一個(gè)類中有如下六個(gè)默認(rèn)成員函數(shù):構(gòu)造函數(shù),析構(gòu)函數(shù),拷貝構(gòu)造函數(shù),拷貝賦值函數(shù),取地址重載函數(shù),const取地址重載函數(shù),其中前四個(gè)成員函數(shù)最重要.后面兩個(gè)成員函數(shù)一般不會(huì)用到 其中這里“默認(rèn)”的意思就是 你不

    2024年02月02日
    瀏覽(25)
  • Java 20 新功能介紹

    Java 20 共帶來 7 個(gè)新特性功能 ,其中三個(gè)是孵化提案,孵化也就是說尚在征求意見階段,未來可能會(huì)刪除此功能。 JEP 描述 分類 429 作用域值(孵化器) Project Loom,Java 開發(fā)相關(guān) 432 Record 模式匹配(第二次預(yù)覽) Project Amber,新的語言特性 433 switch 的模式匹配(第四次預(yù)覽)

    2024年02月03日
    瀏覽(26)
  • Midjourney新功能:角色參照指南

    基本概念 角色參照(Character Reference) :這個(gè)功能允許用戶在不同的圖像生成中保持給定參照角色的一致性。 適用模型 :適用于Midjourney V6和Niji6型號(hào)。 功能亮點(diǎn) 跨風(fēng)格一致性 :可以在不同風(fēng)格(如動(dòng)漫風(fēng)、寫實(shí)風(fēng))中保持角色特征一致。 面部、著裝、發(fā)型調(diào)控 :用戶可以

    2024年04月10日
    瀏覽(42)
  • TypeScript 5.1發(fā)布,新功能更新

    TypeScript 5.1發(fā)布,新功能更新

    1:返回類型增加undefined 這里設(shè)置了一個(gè)別名 fun,當(dāng)時(shí)使用它的時(shí)候,我們必須顯示返回一個(gè) undefined 。 現(xiàn)在你可以直接設(shè)置返回類型: 而不僅限于 void any 。 4.3版本 :? 5.1版本 :? 2:getter可以設(shè)置和 setter 的不相關(guān)類型 在之前版本 ,get 返回類型應(yīng)該為 set 的子類型,如

    2024年02月09日
    瀏覽(24)
  • SOLIDWORKS 2023新功能揭秘(一):3D CAD功能的十大更新

    SolidWorks 3D CAD ?軟件擁有設(shè)計(jì)、模擬、成本估算、可制造性檢查、CAM、可持續(xù)設(shè)計(jì)和數(shù)據(jù)管理等功能,同時(shí)還包含適用于鈑金,焊件,曲面,模具,產(chǎn)品配置,DFM和CAM的專業(yè)工具,支持ECAD/MCAD協(xié)作,復(fù)雜的零部件庫(kù)以及高級(jí)真實(shí)感渲染。更重要的是具有結(jié)構(gòu)和運(yùn)動(dòng)分析功能,

    2024年02月05日
    瀏覽(18)
  • 三星泄露微軟 Copilot 新功能:用自然語言操控各種功能

    三星泄露微軟 Copilot 新功能:用自然語言操控各種功能

    3 月 11 日消息,微軟計(jì)劃本月晚些時(shí)候發(fā)布新款 Surface 電腦和適用于?Windows 11?的 Copilot 新功能,但三星似乎等不及了,在其即將推出的 Galaxy Book4 系列產(chǎn)品宣傳材料中泄露了一些即將到來的 Copilot 功能。 三星官網(wǎng)上發(fā)布的圖片證實(shí)了此前關(guān)于微軟正為其人工智能助手 Copilo

    2024年04月09日
    瀏覽(30)
  • Microsoft Releases .NET 7新功能

    Microsoft Releases .NET 7新功能

    Microsoft Visual Studio是一種統(tǒng)一的開發(fā)體驗(yàn),使開發(fā)人員能夠跨web、云和設(shè)備創(chuàng)建多層應(yīng)用程序。11月8日,微軟發(fā)布了該強(qiáng)大開發(fā)環(huán)境的下一版本:Visual Studio 2022 17.4版。 除了修復(fù)許多頂級(jí)報(bào)告的bug之外,17.4版還包括了許多基于開發(fā)者社區(qū)建議的新功能,包括: Visual Studio的本

    2024年02月06日
    瀏覽(30)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包