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

