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

c++右值引用、移動(dòng)語義、完美轉(zhuǎn)發(fā)

這篇具有很好參考價(jià)值的文章主要介紹了c++右值引用、移動(dòng)語義、完美轉(zhuǎn)發(fā)。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

1.?左值、右值、左值引用以及右值引用

  • 左值:一般指的是在內(nèi)存中有對應(yīng)的存儲(chǔ)單元的值,最常見的就是程序中創(chuàng)建的變量
  • 右值:和左值相反,一般指的是沒有對應(yīng)存儲(chǔ)單元的值(寄存器中的立即數(shù),中間結(jié)果等),例如一個(gè)常量,或者表達(dá)式計(jì)算的臨時(shí)變量
int x = 10 
int y = 20
int z = x + y 
//x, y , z 是左值
//10 , 20,x + y 是右值,因?yàn)樗鼈冊谕瓿少x值操作后即消失,沒有占用任何資源
  • 左值引用:C++中采用 &對變量進(jìn)行引用,這種常規(guī)的引用就是左值引用
  • 右值引用:右值引用最大的作用就是讓一個(gè)左值達(dá)到類似右值的效果(下面程序舉例),讓變量之間的轉(zhuǎn)移更符合“語義上的轉(zhuǎn)移”,以減少轉(zhuǎn)移之間多次拷貝的開銷。右值引用符號(hào)是&&。

例如,對于以下程序,我們要將字符串放到vector中,且我們后續(xù)的代碼中不再用到x:

std::vector<std::string> vec;
std::string x = "abcd";
vec.push_back(x);
std::cout<<"x: "<<x<<"\n";
std::cout<<"vector: "<< vec[0]<<"\n";

//-------------output------------------
// x: abcd
// vector: abcd

?該程序在真正執(zhí)行的過程中,實(shí)際上是復(fù)制了一份字符串x,將其放在vector中,這其中多了一個(gè)拷貝的開銷和內(nèi)存上的開銷。但如果x以及沒有作用了,我們希望做到的是?真正的轉(zhuǎn)移,即x指向的字符串移動(dòng)到vector中,不需要額外的內(nèi)存開銷和拷貝開銷。因此我們希望讓變量 x傳入到push_back?表現(xiàn)的像一個(gè)右值?,這個(gè)時(shí)候就體現(xiàn)右值引用的作用,只需要將x的右值引用傳入就可以。

改進(jìn)成如下代碼:

std::vector<std::string> vec;
std::string x = "abcd";
vec.push_back(std::move(x));              <---------------  使用了std::move,任何的左值/右值通過std::move都轉(zhuǎn)化為右值引用
std::cout<<"x: "<<x<<"\n";
std::cout<<"vector: "<< vec[0]<<"\n";
//-------------output------------------
// x: 
// vector: abcd

可以看到,完成`push_back`后x是空的。

?

?2. 移動(dòng)語義

?移動(dòng)語義是通過移動(dòng)構(gòu)造移動(dòng)賦值避免無意義的拷貝操作。

2.1 使用std::move實(shí)現(xiàn)移動(dòng)構(gòu)造

定義:采用右值引用作為參數(shù)的構(gòu)造函數(shù)又稱作移動(dòng)構(gòu)造函數(shù)。此時(shí)不需要額外的拷貝操作,也不需要新分配內(nèi)存。

使用場景:對于一個(gè)值(比如數(shù)組、字符串、對象等)如果在執(zhí)行某個(gè)操作后不再使用,那么這個(gè)值就叫做將亡值(Expiring Value),因此對于本次操作我們就沒必要對該值進(jìn)行額外的拷貝操作,而是希望直接轉(zhuǎn)移,盡可能減少額外的拷貝開銷,操作后該值也不再占用額外的資源。

使用函數(shù):std::move,任何的左值/右值通過std::move都轉(zhuǎn)化為右值引用

看如下例子,

#include <iostream>
#include <vector>
#include <string>

class A {
  public:
    A(){}
    A(size_t size): size(size), array((int*) malloc(size)) {
        std::cout 
          << "create Array,memory at: "  
          << array << std::endl;
        
    }
    ~A() {
        free(array);
    }
    A(A &&a) : array(a.array), size(a.size) {
        a.array = nullptr;
        std::cout 
          << "Array moved, memory at: " 
          << array 
          << std::endl;
    }
    A(A &a) : size(a.size) {
        array = (int*) malloc(a.size);
        for(int i = 0;i < a.size;i++)
            array[i] = a.array[i];
        std::cout 
          << "Array copied, memory at: " 
          << array << std::endl;
    }
    size_t size;
    int *array;
};
int main() {
    std::vector<A> vec;
    A a = A(10);
    vec.push_back(a);   
    return 0;   
}

//----------------output--------------------
// create Array,memory at: 0x600002a28030 // A a = A(10); 調(diào)用了 構(gòu)造函數(shù)A(size_t size){}
// Array copied, memory at: 0x600002a28050 //vec push的時(shí)候拷貝一份,調(diào)用構(gòu)造函數(shù)A(A &a){}

從輸出可以看到,每次進(jìn)行push_back的時(shí)候,會(huì)重新創(chuàng)建一個(gè)對象,調(diào)用了左值引用A(A &a) : size(a.size)對應(yīng)的構(gòu)造函數(shù),將對象中的數(shù)組重新深拷貝一份。

如果該用右值引用進(jìn)行優(yōu)化,如下

int main () {
    std::vector<A> vec;
    A a = A(10);
    vec.push_back(std::move(a));   
    return 0;   
}

//----------------output--------------------
// create Array,memory at: 0x600003a84030
// Array moved, memory at: 0x600003a84030

可以看到,這個(gè)時(shí)候雖然也重新創(chuàng)建了一個(gè)對象,但是調(diào)用的是這個(gè)構(gòu)造函數(shù)A(A &&a) : array(a.array), size(a.size)(這種采用右值引用作為參數(shù)的構(gòu)造函數(shù)又稱作移動(dòng)構(gòu)造函數(shù)),此時(shí)不需要額外的拷貝操作,也不需要新分配內(nèi)存。

?

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

使用函數(shù):std::forward,如果傳遞的是左值轉(zhuǎn)發(fā)的就是左值引用,傳遞的是右值轉(zhuǎn)發(fā)的就是右值引用。

?

3.1 引用折疊

在具體介紹std::forward之前,需要先了解C++的引用折疊規(guī)則,對于一個(gè)值引用的引用最終都會(huì)被折疊成左值引用或者右值引用。

  • T& & -> T& (對左值引用的左值引用是左值引用)
  • T& && -> T& (對左值引用的右值引用是左值引用)
  • T&& & ->T& (對右值引用的左值引用是左值引用)
  • T&& && ->T&& (對右值引用的右值引用是右值引用)

總結(jié)一句話,只有對于右值引用的右值引用折疊完還是右值引用,其他都會(huì)被折疊成左值引用。

?

3.2 使用std::forward實(shí)現(xiàn)完美轉(zhuǎn)發(fā)

std::forward的作用就是完美轉(zhuǎn)發(fā),確保轉(zhuǎn)發(fā)過程中引用的類型不發(fā)生任何改變,左值引用轉(zhuǎn)發(fā)后一定還是左值引用,右值引用轉(zhuǎn)發(fā)后一定還是右值引用!

下面是一個(gè)使用 std::forward 的例子:

#include <iostream>
#include <utility>
 
void func(int& x) {
    std::cout << "lvalue reference: " << x << std::endl;
}
 
void func(int&& x) {
    std::cout << "rvalue reference: " << x << std::endl;
}
 
template<typename T>
void wrapper(T&& arg) {
    func(std::forward<T>(arg));
}
 
int main() {
    int x = 42;
    wrapper(x);  // lvalue reference: 42
    wrapper(1);  // rvalue reference: 1
    return 0;
}

在上面的例子中,我們定義了兩個(gè)函數(shù) func,一個(gè)接受左值引用,另一個(gè)接受右值引用。然后我們定義了一個(gè)模板函數(shù) wrapper,在 wrapper 函數(shù)中,我們使用 std::forward 函數(shù)將參數(shù) arg 轉(zhuǎn)發(fā)給 func 函數(shù)。通過使用 std::forward,我們可以確保 func 函數(shù)接收到的參數(shù)的左右值特性與原始參數(shù)保持一致。

  • 當(dāng)向wrapper里面?zhèn)魅離的時(shí)候,wrapper推導(dǎo)認(rèn)為 T是一個(gè)左值引用int &,通過引用折疊原則(看萬能引用文章)int && + & = int &,相當(dāng)于wrapper(int& arg),同時(shí)我們知道了T推導(dǎo)為int&,那么在向func傳遞的時(shí)候,就是func(std::forward<int&> (arg)) ,那么func會(huì)以左值引用的形式 func(int& x) 調(diào)用arg。
  • 當(dāng)向wrapper里面?zhèn)魅?的時(shí)候,wrapper推導(dǎo)認(rèn)為T是一個(gè)右值引用int&& ,通過引用折疊原則,int && + && =int&& ,相當(dāng)于wrapper(int&& arg),同時(shí)我們知道了T推導(dǎo)為int&&,那么在向func傳遞的時(shí)候,就是func(std::forward<int&&>(arg)),那么func會(huì)以左值引用的形式func(int&& x)調(diào)用arg。

?

另一個(gè)例子:

class Test{};

void B(Test& a) {cout << "B&"  << endl;}
void B(Test&& a) {cout << "B&&" << endl;}
template<typename T> void A(T &&a) { B(std::forward<T>(a)); }

int main()
{
  Test a;
  A(std::move(a));
  A(a);
  return 0;    
}


//////
//輸出結(jié)果
B&&
B&

?

?

?

參考鏈接:https://zhuanlan.zhihu.com/p/469607144

https://www.jb51.net/article/278300.htm文章來源地址http://www.zghlxwxcb.cn/news/detail-745905.html

到了這里,關(guān)于c++右值引用、移動(dòng)語義、完美轉(zhuǎn)發(fā)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

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

相關(guān)文章

  • C++左值右值完美轉(zhuǎn)發(fā)轉(zhuǎn)移

    英文含義: 左值(Lvalue) : Locator value ,意味著它指向一個(gè)具體的內(nèi)存位置。 右值(Rvalue) : Read value ,指的是可以讀取的數(shù)據(jù),但不一定指向一個(gè)固定的內(nèi)存位置。 定義 左值 :指的是一個(gè)持久的內(nèi)存地址。左值可以出現(xiàn)在賦值操作的左側(cè)或右側(cè)。例如,變量、數(shù)組的元

    2024年03月10日
    瀏覽(35)
  • 【C++11】 initializer_list | 右值引用 | 移動(dòng)構(gòu)造 | 完美轉(zhuǎn)發(fā)

    【C++11】 initializer_list | 右值引用 | 移動(dòng)構(gòu)造 | 完美轉(zhuǎn)發(fā)

    { } 初始化 C++11 擴(kuò)大了括號(hào)括起的列表(初始化列表)的使用范圍,使其可用于所有的內(nèi)置類型和用戶自定義類型, 使用初始化列表,可添加等號(hào)(=),也可不添加 將1賦值給x1,x2處省略了賦值符號(hào),將5賦值給x2 同樣也可以將new開辟4個(gè)int的空間初始化為0 創(chuàng)建對象時(shí),可以使用列

    2024年02月08日
    瀏覽(23)
  • c++積累8-右值引用、移動(dòng)語義

    c++積累8-右值引用、移動(dòng)語義

    1.1 背景 c++98中的引用很常見,就是給變量取個(gè)別名,具體可以參考c++積累7 在c++11中,增加了右值引用的概念,所以c++98中的引用都稱為左值引用 1.2 定義 右值引用就是給右值取個(gè)名字,右值有了名字之后就成了普通變量,可以像使用左值一樣使用。 語法:數(shù)據(jù)類型 變量名

    2023年04月23日
    瀏覽(17)
  • 【C++學(xué)習(xí)】C++11——新特性 | 右值引用 | 完美轉(zhuǎn)發(fā)

    【C++學(xué)習(xí)】C++11——新特性 | 右值引用 | 完美轉(zhuǎn)發(fā)

    ??作者:一只大喵咪1201 ??專欄:《C++學(xué)習(xí)》 ??格言: 你只管努力,剩下的交給時(shí)間! C++的發(fā)展截至到目前為止,雖然版本有很多,但是C++11則帶來了數(shù)量可觀的變化,其中包含了約140個(gè)新特性,以及對C++03標(biāo)準(zhǔn)中約600個(gè)缺陷的修正,這使得C++11更像是從C++98/03中孕育出的一

    2024年02月06日
    瀏覽(20)
  • 【C++】—— C++11新特性之 “右值引用和移動(dòng)語義”

    【C++】—— C++11新特性之 “右值引用和移動(dòng)語義”

    前言: 本期,我們將要的介紹有關(guān) C++右值引用 的相關(guān)知識(shí)。對于本期知識(shí)內(nèi)容,大家是必須要能夠掌握的,在面試中是屬于重點(diǎn)考察對象。 目錄 (一)左值引用和右值引用 1、什么是左值?什么是左值引用? 2、什么是右值?什么是右值引用? (二)左值引用與右值引用比

    2024年02月11日
    瀏覽(21)
  • 詳解 C++ 左值、右值、左值引用以及右值引用

    詳解 C++ 左值、右值、左值引用以及右值引用

    左值是一個(gè)表示數(shù)據(jù)的表達(dá)式,比如: 變量名、解引用的指針變量 。一般地,我們可以 獲取它的地址 和 對它賦值 ,但被 const 修飾后的左值,不能給它賦值,但是仍然可以取它的地址。 總體而言,可以取地址的對象就是左值。 右值也是一個(gè)表示數(shù)據(jù)的表達(dá)式,比如: 字面

    2023年04月08日
    瀏覽(33)
  • 從C語言到C++_33(C++11_上)initializer_list+右值引用+完美轉(zhuǎn)發(fā)+移動(dòng)構(gòu)造/賦值

    從C語言到C++_33(C++11_上)initializer_list+右值引用+完美轉(zhuǎn)發(fā)+移動(dòng)構(gòu)造/賦值

    目錄 1.?列表初始化initializer_list 2. 前面提到的一些知識(shí)點(diǎn) 2.1 小語法 2.2 STL中的一些變化 3. 右值和右值引用 3.1?右值和右值引用概念 3.2?右值引用類型的左值屬性 3.3?左值引用與右值引用比較 3.4?右值引用的使用場景 3.4.1 左值引用的功能和短板 3.4.2?移動(dòng)構(gòu)造 3.4.3?移動(dòng)賦值

    2024年02月12日
    瀏覽(36)
  • [開發(fā)語言][c++]:左值、右值、左值引用、右值引用和std::move()

    寫在前面: 如果你也被 左值、右值、左值引用、右值引用和std::move 搞得焦頭爛額,相關(guān)概念和理解不夠深入,或者認(rèn)識(shí)模棱兩可,那么這篇文章將非常的適合你,耐心閱讀,相信一定會(huì)有所收獲~~ 左值: 可以取地址、位于等號(hào)左邊 – 表達(dá)式結(jié)束后依然存在的持久對象

    2024年02月02日
    瀏覽(14)
  • 【C++】 C++11(右值引用,移動(dòng)語義,bind,包裝器,lambda,線程庫)

    【C++】 C++11(右值引用,移動(dòng)語義,bind,包裝器,lambda,線程庫)

    C++11是C++語言的一次重大更新版本,于2011年發(fā)布,它包含了一些非常有用的新特性,為開發(fā)人員提供了更好的編程工具和更好的編程體驗(yàn),使得編寫高效、可維護(hù)、安全的代碼更加容易。 一些C++11的新增特性包括: 強(qiáng)制類型枚舉,使得枚舉類型的通常行為更加可靠和容易控制

    2024年02月10日
    瀏覽(20)
  • 初識(shí)C++之左值引用與右值引用

    初識(shí)C++之左值引用與右值引用

    目錄 一、左值引用與右值引用 1. 左值和右值的概念 1.1 左值 1.2?右值 ?1.3 左值與右值的區(qū)分 2. 左值引用與右值引用 2.1 左值引用與右值引用的使用方法 2.2?左值引用的可引用范圍 2.3?右值引用的可引用范圍 3. 右值引用的作用 3.1 減少傳值返回的拷貝 3.2 插入時(shí)的右值引用 4

    2023年04月26日
    瀏覽(20)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包