最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++模板編程特性之移動(dòng)語(yǔ)義

 更新時(shí)間:2022年08月23日 15:28:36   作者:努力的張張  
首先,移動(dòng)語(yǔ)義和完美轉(zhuǎn)發(fā)這兩個(gè)概念是在C++的模板編程的基礎(chǔ)上,新增的特性,主要是配合模板來(lái)使用。本篇會(huì)從C++的值類(lèi)型,到移動(dòng)拷貝與移動(dòng)賦值來(lái)理解移動(dòng)語(yǔ)義與完美轉(zhuǎn)發(fā)

C++的值類(lèi)型

我們知道,每個(gè)變量都有類(lèi)型,或整形或字符型等來(lái)進(jìn)行了分類(lèi),不僅如此,C++表達(dá)式(帶有操作數(shù)的操作符、字面量、變量名等)在類(lèi)型的屬性上,還有一種屬性,即值類(lèi)別(value category)。且每個(gè)表達(dá)式只屬于三種基本值尖別中的一種:左值(lvalue),右值(rvalue),將亡值(xvalue),每個(gè)值類(lèi)別都與某種引用類(lèi)型對(duì)應(yīng)。

其中,左值和將亡值成為泛左值(generalized value,gvalue),純右值和將亡值合稱為右值(right value,rvalue)。

一般我們講,左值就是可以取地址的,具有名字的,比如 int a; a是變量的名字,&a是變量的地址,a就是左值。那么右值呢,自然就是不可以取地址的,比如int b=10; 而這個(gè)10就是一個(gè)右值,在內(nèi)存中不會(huì)分配有地址,自然也不能取地址。

將亡值,則是指在調(diào)用某個(gè)函數(shù)退出返回時(shí),如果函數(shù)有返回值,那么就會(huì)有將亡值的存在,為什么稱之為將亡值,就是說(shuō)這個(gè)值在函數(shù)作用域創(chuàng)建,但由于函數(shù)返回結(jié)束,局部變量都會(huì)銷(xiāo)毀,故會(huì)產(chǎn)生一個(gè)將亡值來(lái)接收這個(gè)值,完成賦值的任務(wù)。

從上圖也可以看出,將亡值既可能轉(zhuǎn)為左值,也可能成為右值,那么關(guān)鍵就在于要看是否具有名字了。

下面看這樣一段程序:

#include<iostream>
#include<type_traits>
using namespace std;
class MyString
{
private:
	char* str; // heap;
public:
	MyString(const char* p = nullptr) :str(nullptr)
	{
		if (p != nullptr)
		{
			int n = strlen(p) + 1;
			str = new char[n];
			strcpy_s(str, n, p);
		}
		cout << "Create MyString: " << this << endl;
	}
	MyString(const MyString& st)
	{
		if(st.str!=NULL)
		str = st.str;
		cout << "Copy Create MyString: " << this << endl;
	}
	MyString& operator=(const MyString& st)
	{
		if (st.str != NULL)
		str = st.str;
		cout << this << " operator=(const MyString &):  " << &st << endl;
		return *this;
	}
	~MyString()
	{
		delete[]str;
		str = nullptr;
		cout << "Destroy MyString : " << this << endl;
	}
	void PrintString() const
	{
		if (str != nullptr)
		{
			cout << str << endl;
		}
	}
};
int main()
{
	MyString *a=new MyString("lisa");
	MyString *b = a;
	delete b;
	a->PrintString();
	return 0;
}

MyString類(lèi)型成員有指針變量,且采用淺拷貝方式。當(dāng)程序運(yùn)行時(shí),可以看到,兩個(gè)指針指向了同一個(gè)地址,此時(shí),若釋放了b指針,再以a指針訪問(wèn)指針成員,就會(huì)出現(xiàn)問(wèn)題。

還有,當(dāng)函數(shù)以值類(lèi)型返回,構(gòu)造臨時(shí)對(duì)象,若有指針變量,且采用淺拷貝,就會(huì)出現(xiàn)多次析構(gòu)的問(wèn)題,導(dǎo)致程序崩潰。

當(dāng)我們將程序都改為深拷貝時(shí),深拷貝又會(huì)導(dǎo)致,程序多次騷擾對(duì)空間,此時(shí)就提出了move語(yǔ)義。

std::move

std::move其實(shí)并沒(méi)有移動(dòng)任何東西,它唯一的功能是將一個(gè)左值強(qiáng)制轉(zhuǎn)化為右值引用,繼而可以通過(guò)右值引用使用該值,以用于移動(dòng)語(yǔ)義。從實(shí)現(xiàn)上講,move基本等同于一個(gè)類(lèi)型轉(zhuǎn)換。

值得注意的是,通過(guò)move轉(zhuǎn)化成右值后,被轉(zhuǎn)化的左值的生命周期并沒(méi)有隨著左右值的轉(zhuǎn)化而改變。但通常情況下,我們需要轉(zhuǎn)換成右值引用的還是一個(gè)確定生命期即將結(jié)束的對(duì)象。

右值引用與移動(dòng)構(gòu)造和移動(dòng)賦值

在c++11中增加了右值引用的概念,即對(duì)右值的引用,通過(guò)右值引用,可以延長(zhǎng)右值的生命期。我們都知道左值引用是變量值的別名,那么右值引用則是不具名變量的別名。

右值引用是不能綁定到任何左值的,但有個(gè)例外,常量左值是一個(gè)萬(wàn)能引用,可以引用任何值,包括右值引用。

class MyString
{
private:
	char* str; // heap;
public:
	MyString(const char* p = nullptr) :str(nullptr)
	{
		if (p != nullptr)
		{
			int n = strlen(p) + 1;
			str = new char[n];
			strcpy_s(str, n, p);
		}
		cout << "Create MyString: " << this << endl;
	}
	MyString(const MyString& st)
	{
		if (st.str != nullptr)
		{
			int n = strlen(st.str) + 1;
			str = new char[n];
			strcpy_s(str, n, st.str);
		}
		cout << "Copy Create MyString: " << this << endl;
	}
	MyString& operator=(const MyString& st)
	{
		if (this != &st && str != st.str)
		{
			delete[]str;
			if (st.str != nullptr)
			{
				int n = strlen(st.str) + 1;
				str = new char[n];
				strcpy_s(str, n, st.str);
			}
		}
		cout << this << " operator=(const MyString &):  " << &st << endl;
		return *this;
	}
	MyString(MyString&& st)
	{
		str = st.str;
		st.str = nullptr;
		cout << "Move Copy Create MyString" << this << endl;
	}
	MyString& operator=(MyString&& st)
	{
		if (this == &st) return *this;
		if (this->str == st.str)
		{
			st.str = nullptr;
			return *this;
		}
		delete[]str;
		str = st.str;
		st.str = nullptr;
		cout << "Move operator=(MyString &&)" << endl;
		return *this;
	}
	~MyString()
	{
		delete[]str;
		str = nullptr;
		cout << "Destroy MyString : " << this << endl;
	}
	void PrintString() const
	{
		if (str != nullptr)
		{
			cout << str << endl;
		}
	}
};
int main()
{
	const MyString stra("hello");
	MyString strb;
	strb = std::move(stra);//調(diào)用普通的賦值方法
	strb.PrintString();
	return 0;
}

這里的move還是調(diào)用普通的賦值函數(shù),并未做到真正的資源轉(zhuǎn)移,但是若寫(xiě)成如下結(jié)構(gòu):

int main()
{
	const MyString stra("hello");
	MyString strb;
	//strb = std::move(stra);//調(diào)用普通的賦值方法
	strb = (MyString&&)stra;
	strb.PrintString();
	return 0;
}

通過(guò)右值引用,可以延長(zhǎng)右值的生命期。從而,有了右值引用出現(xiàn),這個(gè)時(shí)候配合移動(dòng)構(gòu)造與移動(dòng)賦值,就可以完成資源轉(zhuǎn)移了。

然后,我們?cè)倏匆粋€(gè)例子:

MyString& fun()
{
	MyString st=("newdata");
	return st;//xvalue
}
int main()
{
	MyString("zhangsan").PrintString();
	const MyString& a = fun();
	a.PrintString();
	MyString& b = fun();
	b.PrintString();
	return 0;
}

在程序運(yùn)行時(shí),會(huì)發(fā)現(xiàn)程序崩潰了,原因是:

函數(shù)中返回局部對(duì)象的引用,因?yàn)楹瘮?shù)調(diào)用結(jié)束會(huì)銷(xiāo)毀局部對(duì)象,而引用則就成為了非法的訪問(wèn)。因?yàn)椴灰诤瘮?shù)中返回局部對(duì)象的引用。

若我們將fun()函數(shù)的返回改為右值引用呢?

MyString&& fun()
{
	return MyString("newdata");
}
int main()
{
	MyString("zhangsan").PrintString();
	const MyString& a = fun();//x
	a.PrintString();
	//MyString& b = fun();
	//b.PrintString();
	MyString&& c = fun();//x
	c.PrintString();
	MyString&& d = c;//error
	return 0;
}

將亡值回去的時(shí)候,就得看看有沒(méi)有具名,一旦具名就是左值了,否則是右值

可以發(fā)現(xiàn),右值引用是不具名的,但是右值引用本身卻是個(gè)左值,經(jīng)過(guò)右值引用b接收后,就已經(jīng)變成了左值,具有了名字。

到此這篇關(guān)于C++模板編程特性之移動(dòng)語(yǔ)義的文章就介紹到這了,更多相關(guān)C++移動(dòng)語(yǔ)義內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++11系列學(xué)習(xí)之可調(diào)用對(duì)象包裝器和綁定器

    C++11系列學(xué)習(xí)之可調(diào)用對(duì)象包裝器和綁定器

    這篇文章主要介紹了C++11系列學(xué)習(xí)之可調(diào)用對(duì)象包裝器和綁定器,下文基于C++的相關(guān)資料展開(kāi)詳細(xì)內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-04-04
  • 詳解C語(yǔ)言中return與exit的區(qū)別

    詳解C語(yǔ)言中return與exit的區(qū)別

    這篇文章主要介紹了詳解C語(yǔ)言中return與exit的區(qū)別的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家理解這部分內(nèi)容,需要的朋友可以參考下
    2017-10-10
  • C語(yǔ)言中g(shù)etchar()函數(shù)的用法小結(jié)

    C語(yǔ)言中g(shù)etchar()函數(shù)的用法小結(jié)

    這篇文章主要介紹了C語(yǔ)言中g(shù)etchar()函數(shù)的用法,getchar是輸入函數(shù),輸入的過(guò)程是什么呢,本文給大家詳細(xì)講解,對(duì)C語(yǔ)言getchar()函數(shù)相關(guān)知識(shí)感興趣的朋友一起看看吧
    2022-10-10
  • LintCode 堆化詳解及實(shí)例代碼

    LintCode 堆化詳解及實(shí)例代碼

    這篇文章主要介紹了LintCode 堆化詳解及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • 深入分析C++中執(zhí)行多個(gè)exe文件方法的批處理代碼介紹

    深入分析C++中執(zhí)行多個(gè)exe文件方法的批處理代碼介紹

    本篇文章是對(duì)C++中執(zhí)行多個(gè)exe文件方法的批處理代碼進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++中auto類(lèi)型說(shuō)明符詳解(附易錯(cuò)實(shí)例)

    C++中auto類(lèi)型說(shuō)明符詳解(附易錯(cuò)實(shí)例)

    這篇文章主要給大家介紹了關(guān)于C++中auto類(lèi)型說(shuō)明符的相關(guān)資料,文中還附易錯(cuò)實(shí)例,在C++11中引入了auto類(lèi)型說(shuō)明符,用它就能讓編譯器替我們?nèi)シ治霰磉_(dá)式所屬的類(lèi)型,需要的朋友可以參考下
    2023-07-07
  • VS2019中QT連接及使用的方法步驟

    VS2019中QT連接及使用的方法步驟

    這篇文章主要介紹了VS2019中QT連接及使用的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • 關(guān)于C語(yǔ)言和命令行之間的交互問(wèn)題

    關(guān)于C語(yǔ)言和命令行之間的交互問(wèn)題

    這篇文章主要介紹了C語(yǔ)言和命令行之間的交互,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-07-07
  • 一篇文章了解c++中的new和delete

    一篇文章了解c++中的new和delete

    C語(yǔ)言提供了malloc和free兩個(gè)系統(tǒng)函數(shù),完成對(duì)堆內(nèi)存的申請(qǐng)和釋放,而C++則提供了兩個(gè)關(guān)鍵字new和delete,下面這篇文章主要給大家介紹了如何通過(guò)一篇文章了解c++中new和delete的相關(guān)資料,需要的朋友可以參考下
    2021-12-12
  • C++ float轉(zhuǎn)std::string 小數(shù)位數(shù)控制問(wèn)題

    C++ float轉(zhuǎn)std::string 小數(shù)位數(shù)控制問(wèn)題

    這篇文章主要介紹了C++ float轉(zhuǎn)std::string 小數(shù)位數(shù)控制問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11

最新評(píng)論

新乡市| 喀什市| 霍山县| 漯河市| 江口县| 山阴县| 柳林县| 库伦旗| 谢通门县| 青冈县| 祁阳县| 宜城市| 林甸县| 义乌市| 武鸣县| 上饶县| 财经| 甘谷县| 广饶县| 都江堰市| 定安县| 遂昌县| 明溪县| 江源县| 邮箱| 宁津县| 家居| 永善县| 富民县| 芜湖县| 津南区| 建始县| 延津县| 峨眉山市| 肥乡县| 深泽县| 青海省| 大同县| 九江市| 正镶白旗| 忻城县|