一文帶你了解C++中的右值引用與移動語義
意義
充分利用臨時對象,避免拷貝。
左值右值
值類別
在 C++11之后,C++根據(jù)
- 被標識:可通過不同標識符指代同一實體。(對象/內(nèi)存)
- 可移動:可作為移動語義函數(shù)的參數(shù),例如移動構(gòu)造,移動賦值。
將值分為以下類別:
泛左值:被標識
- 左值:被標識且不可移動
- 將亡值:被標識可移動
右值:可移動
- 將亡值:被標識可移動
- 純右值:不被標識且可移動
左值
int a = 1;
a是一個左值,左值是關(guān)聯(lián)了名稱的內(nèi)存位置。
純右值
int a = 1;
1是一個純右值,純右值是指不被標識且可移動的值,例如字面量。
將亡值
using std::string; string get() { string ret = "abc"; return ret; } string str = get();
get() 函數(shù)調(diào)用會產(chǎn)生一個臨時變量賦給str,這個臨時變量是將亡值,此時的賦值是移動語義(c++11之前是復(fù)制語義)。
左值引用
int a = 1; int& a_lref = a;
a_lref是左值引用
右值引用
int&& rref = 1;
rref是右值引用(rref是類型為右值引用的左值)
std::move()
void foo(int&& rref) { } int a = 1; foo(std::move(a));
std::move本質(zhì)是類型轉(zhuǎn)換,即把左值轉(zhuǎn)換成右值
注意:被轉(zhuǎn)換的對象不應(yīng)再被使用,否則結(jié)果難以預(yù)計(通常內(nèi)存會被轉(zhuǎn)移)
移動構(gòu)造&移動賦值運算符重載
class Foo { public: Foo() { m_data = malloc(32); } Foo(const Foo& rhs) { if(m_data == nullptr) { m_data = malloc(32); } memcopy(m_data,rhs.m_data,32); } Foo& operator = (const Foo& rhs) { if(m_data == nullptr) { m_data = malloc(32); } memcopy(m_data,rhs.m_data,32); return *this; } Foo(Foo&& rhs) noexcept { m_data = rhs.m_data; rhs.m_data = nullptr; } Foo& operator = (Foo&& rhs) noexcept { m_data = rhs.m_data; rhs.m_data = nullptr; return *this; } private: void* m_data }
移動構(gòu)造的本質(zhì)就是內(nèi)存資源所有權(quán)的轉(zhuǎn)移
測試&驗證
#include <iostream> #include <cstdlib> #define LOG(Args) std::cout << "==== " << Args << " ====" << std::endl namespace My { class Vector { public: Vector() noexcept { LOG("Ctor"); m_data = new int[] {0, 0, 0, }; } ~Vector() { LOG("Dector"); m_data = new int[] {0, 0, 0, }; } Vector(const Vector& rhs) { LOG("Copy"); if (m_data == nullptr) { m_data = new int[3]; } memcpy(m_data, rhs.m_data, 3 * sizeof(int)); } Vector& operator = (const Vector& rhs) { LOG("Copy Operator = "); if (m_data == nullptr) { m_data = new int[3]; } memcpy(m_data, rhs.m_data, 3 * sizeof(int)); return *this; }; Vector& operator = (Vector&& rhs) noexcept { LOG("Move Operator = "); m_data = rhs.m_data; rhs.m_data = nullptr; return *this; }; Vector(Vector&& rhs) noexcept { LOG("Move"); m_data = rhs.m_data; rhs.m_data = nullptr; } void print() { std::cout << "X = " << m_data[0] << " , " << "Y = " << m_data[1] << " , " << "Z = " << m_data[2] << std::endl; } void set(int x,int y,int z) { m_data[0] = x; m_data[1] = y; m_data[2] = z; } private: int* m_data; }; } My::Vector Get() { My::Vector vec; vec.set(4, 5, 6); return vec; } void main() { My::Vector vec1; My::Vector vec2; LOG("vec1"); vec1.print(); vec1.set(0, 1, 2); LOG("vec1"); vec1.print(); vec1 = vec2; LOG("vec1"); vec1.print(); vec1 = std::move(vec2); LOG("vec1"); vec1.print(); My::Vector* vp1 = new My::Vector(); LOG("vp1"); vp1->print(); My::Vector* vp2 = new My::Vector(*vp1); LOG("vp2"); vp2->print(); My::Vector* vp3 = new My::Vector(std::move(*vp1)); LOG("vp3"); vp3->print(); My::Vector* vp4 = new My::Vector(Get()); LOG("vp4"); vp4->print(); }
輸出
到此這篇關(guān)于一文帶你了解C++中的右值引用與移動語義 的文章就介紹到這了,更多相關(guān)C++右值引用 移動語義 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Qt中QtWebEngine加載本地網(wǎng)頁跨域問題的總結(jié)
本文主要介紹了Qt中QtWebEngine加載本地網(wǎng)頁跨域問題的總結(jié),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2022-04-04