C++基本用法實(shí)踐之移動(dòng)語(yǔ)義詳解
概述
移動(dòng)
移動(dòng)(move)語(yǔ)義C++引入了一種新的內(nèi)存優(yōu)化,以避免不必要的拷貝。在構(gòu)造或者賦值的時(shí)候,如果實(shí)參是右值(或者左值由std::move轉(zhuǎn)換成右值),便會(huì)匹配移動(dòng)語(yǔ)義的函數(shù)調(diào)用如下述舉例的Str(Str&& obj)
。
移動(dòng)語(yǔ)義的本質(zhì)是將資源(內(nèi)存/句柄)轉(zhuǎn)移給另一個(gè)對(duì)象,被轉(zhuǎn)移資源的對(duì)象不應(yīng)再被使用。(這個(gè)概念有點(diǎn)像仙俠小說(shuō)中的奪舍,奪舍成功的人獲取被奪舍的人的身體(資源)),如下面?zhèn)未a:
class Obj { data Obj(){ data = malloc(100) } // 移動(dòng) (奪舍) Obj(Obj&& other){ data = other.data other.data = nullptr } }
右值
右值直觀理解是等號(hào)右邊的值(大概如此,并不準(zhǔn)確),右值的概念指代的東西比較多,大概是指不可尋址的值(也有例外)。我覺(jué)得這個(gè)不必太過(guò)糾結(jié),記住幾個(gè)常見(jiàn)的即可:
- 臨時(shí)對(duì)象:如函數(shù)返回的臨時(shí)對(duì)象(下面有舉例)
- 字面量
- 顯式std::move()轉(zhuǎn)換的值
- 沒(méi)有捕獲參數(shù)的lambda
C++ 值類(lèi)別表
在 C++11之后,C++根據(jù)
- 被標(biāo)識(shí):可通過(guò)不同標(biāo)識(shí)符指代同一實(shí)體。(對(duì)象/內(nèi)存)
- 可移動(dòng):可作為移動(dòng)語(yǔ)義函數(shù)的參數(shù),例如移動(dòng)構(gòu)造,移動(dòng)賦值。
將值分為以下類(lèi)別:
泛左值:被標(biāo)識(shí)
- 左值:被標(biāo)識(shí)且不可移動(dòng)
- 將亡值:被標(biāo)識(shí)可移動(dòng)
右值:可移動(dòng)
- 將亡值:被標(biāo)識(shí)可移動(dòng)
- 純右值:不被標(biāo)識(shí)且可移動(dòng)
用法舉例
參考測(cè)試項(xiàng)目代碼ModernCppTest/modrenc_rvalueref_stdmove.cpp
主要內(nèi)容:
- 移動(dòng)語(yǔ)義下的構(gòu)造和賦值
- 移動(dòng)還是拷貝的重載匹配
- C++ 優(yōu)化臨時(shí)對(duì)象(連加產(chǎn)生的中間臨時(shí)對(duì)象)嘗試調(diào)用移動(dòng)語(yǔ)義
#include "ModernCppTestHeader.h" #include <string> using std::string; namespace n_rvalueref { class Str { public: Str() { LOG("無(wú)參構(gòu)造"); this->str = new string(); } Str(const string& str) { LOG("有參構(gòu)造 str = " << str); this->str = new string(str); } Str(const Str& obj) { LOG("拷貝構(gòu)造 obj.str = " << *obj.str); this->str = new string(*obj.str); } Str(Str&& obj) noexcept { LOG("移動(dòng)構(gòu)造 obj.str = " << *obj.str); this->str = std::move(obj.str); // 被移動(dòng)的對(duì)象不應(yīng)該再被使用了 obj.str = nullptr; } Str& operator=(Str&& v) noexcept { LOG("移動(dòng)語(yǔ)義 operator = "); if (this != &v) { this->str = std::move(v.str); } return *this; } Str operator+(const Str& v) { string s = *this->str + *v.str; return Str(s); } void Log() { LOG(str); } string* str; }; } using n_rvalueref::Str; // 右值引用&移動(dòng)語(yǔ)義 void rvalueref_stdmove_test() { LOG_FUNC(); LOG_TAG("拷貝構(gòu)造"); { Str t1("A"); Str t2 = t1; LOG_VAR(*t2.str); } LOG_TAG("移動(dòng)構(gòu)造, 注意被移動(dòng)的對(duì)象t1不應(yīng)再被使用"); { // t1是左值,使用std::move強(qiáng)制轉(zhuǎn)換成右值 Str t1("A"); Str t2 = std::move(t1); LOG_VAR(*t2.str); } LOG_TAG("移動(dòng)語(yǔ)義的運(yùn)算符重載,注意運(yùn)算符重載發(fā)生賦值運(yùn)算(這個(gè)例子),而不是構(gòu)造運(yùn)算(上個(gè)例子)"); { Str t1("A"); Str t2; t2 = std::move(t1); } LOG_TAG("除了上述顯示使用std::move轉(zhuǎn)換,常見(jiàn)的容易忽視的發(fā)生移動(dòng)構(gòu)造場(chǎng)合列舉"); { LOG("---1 連續(xù)加法產(chǎn)生的臨時(shí)對(duì)象,c++會(huì)嘗試使用移動(dòng)語(yǔ)義進(jìn)行優(yōu)化"); Str t1("A"); Str t2("B"); Str t3("C"); Str t4; t4 = t1 + t2 + t3; LOG("---2 函數(shù)返回的臨時(shí)對(duì)象,c++會(huì)嘗試使用移動(dòng)語(yǔ)義進(jìn)行優(yōu)化"); auto f = []() { auto s = Str("Hi"); return s; }; Str t5 = f(); /* - 在容器中插入或刪除元素:比如 std::vector::push_back,如果傳遞給它的是右值,它就會(huì)使用移動(dòng)語(yǔ)義。 - 在標(biāo)準(zhǔn)庫(kù)算法中:許多標(biāo)準(zhǔn)庫(kù)算法,比如 std::sort,std::partition 等,在進(jìn)行元素交換時(shí)會(huì)使用移動(dòng)語(yǔ)義。 - 在 std::swap 中:std::swap 會(huì)使用移動(dòng)語(yǔ)義來(lái)交換兩個(gè)對(duì)象。 */ } }
到此這篇關(guān)于C++基本用法實(shí)踐之移動(dòng)語(yǔ)義詳解的文章就介紹到這了,更多相關(guān)C++移動(dòng)語(yǔ)義內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實(shí)現(xiàn)LeetCode(167.兩數(shù)之和之二 - 輸入數(shù)組有序)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(167.兩數(shù)之和之二 - 輸入數(shù)組有序),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08C++使用easyX庫(kù)實(shí)現(xiàn)三星環(huán)繞效果流程詳解
EasyX是針對(duì)C/C++的圖形庫(kù),可以幫助使用C/C++語(yǔ)言的程序員快速上手圖形和游戲編程。這篇文章主要介紹了C++使用easyX庫(kù)實(shí)現(xiàn)三星環(huán)繞效果,需要的可以參考一下2022-10-10OpenCV輪廓檢測(cè)之boundingRect繪制矩形邊框
在進(jìn)行文本檢測(cè)時(shí),我們常常會(huì)用矩形邊框?qū)z測(cè)到的內(nèi)容框除。這篇文章主要為大家介紹的是OpenCV中能實(shí)現(xiàn)這一效果的函數(shù):boundingRect,感興趣的同學(xué)可以學(xué)習(xí)一下2021-12-12講解C語(yǔ)言編程中指針賦值的入門(mén)實(shí)例
這篇文章主要介紹了講解C語(yǔ)言編程中指針賦值的入門(mén)實(shí)例,通過(guò)const int i與int *const pi這樣兩個(gè)例子來(lái)分析指針的賦值和地址指向,需要的朋友可以參考下2015-12-12基于C++ list中erase與remove函數(shù)的使用詳解
本篇文章是對(duì)C++ list中erase與remove函數(shù)的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05將CString字符串輸入轉(zhuǎn)化成整數(shù)的實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇將CString字符串輸入轉(zhuǎn)化成整數(shù)的實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-09-09C語(yǔ)言實(shí)現(xiàn)圖書(shū)管理系統(tǒng)(文件數(shù)據(jù)庫(kù))
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)圖書(shū)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03