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

C++深入右值引用之移動語義與完美轉發(fā)(最新推薦)

 更新時間:2026年05月12日 09:27:26   作者:無限進步_  
本文給大家介紹了C++深入右值引用之移動語義與完美轉發(fā),文章討論了移動構造與移動賦值的概念,以及它們在容器中的應用,感興趣的朋友一起看看吧

1. 左值與右值

左值和右值不是新概念,C++98就有,但C++11賦予了它們更重要的地位。

  • 左值:可以取地址的表達式,有持久狀態(tài)。變量、解引用的指針、數(shù)組元素都是左值。
  • 右值:不能取地址。字面量、臨時對象、表達式求值的中間結果。
int* p = new int(0);
int b = 1;
const int c = b;
*p = 10;            // *p 是左值
string s("hello");
s[0] = 'x';         // s[0] 是左值
10;                 // 右值
x + y;              // 右值
string("hello");    // 右值
// cout << &10;     // 錯誤:右值不能取地址

C++11進一步細化了:右值分為純右值(字面量、臨時對象等)和將亡值move返回的右值引用)。泛左值包含左值和將亡值。這些概念不必死記,關鍵是記住核心區(qū)別:能否取地址。

2. 左值引用與右值引用

左值引用(T&)給左值取別名,右值引用(T&&)給右值取別名。

int& r1 = b;          // 左值引用綁定左值
int&& rr1 = 10;       // 右值引用綁定右值
double&& rr2 = x + y;
string&& rr3 = string("hello");

幾個規(guī)則:

  • 左值引用不能直接綁定右值,但const左值引用可以。
  • 右值引用不能直接綁定左值,但可以通過std::move轉換。
const int& cr = 10;           // OK
int&& rr4 = move(b);          // OK,move后的b仍可使用但資源已被取走

move()本質上是一個強制類型轉換:static_cast<remove_reference_t<T>&&>(arg)。它本身不移動任何東西,只是給了你一個右值引用,真正的動作由移動構造函數(shù)或移動賦值完成。

有一個容易困惑的點:右值引用變量本身的表達式屬性是左值。因為它有名字、可以取地址。

int&& rr = 10;
cout << &rr << endl;   // 可以取地址,rr是左值
int& lr = rr;          // OK,rr作為左值可以綁定左值引用
// int&& rr2 = rr;     // 錯誤,rr是左值,不能直接綁定右值引用
int&& rr2 = move(rr);  // OK

這個設計看似別扭,但恰恰是移動語義能正常工作的基礎——后面會看到。

3. 移動構造與移動賦值

左值引用已經(jīng)在函數(shù)傳參和返回值中減少了大部分拷貝,但有一種場景它搞不定:返回局部對象。

string addStrings(string num1, string num2) {
    string str;
    // ... 構建str ...
    return str;  // str是局部對象,函數(shù)結束就銷毀,不能傳引用返回
}

C++98被迫拷貝,C++11通過移動語義解決了這個問題:既然str馬上就要銷毀,把它的資源“偷”過來就行,沒必要深拷貝。

移動構造和移動賦值接受一個右值引用參數(shù),核心操作是交換資源,而不是復制。

namespace demo {
class string {
public:
    string(const char* str = "")
        : _size(strlen(str)), _capacity(_size)
    {
        _str = new char[_capacity + 1];
        strcpy(_str, str);
    }
    // 拷貝構造
    string(const string& s) {
        // 深拷貝...
    }
    // 移動構造
    string(string&& s) {
        swap(s);   // 直接把s的資源換到自己身上
    }
    // 拷貝賦值
    string& operator=(const string& s) {
        // 深拷貝...
    }
    // 移動賦值
    string& operator=(string&& s) {
        swap(s);
        return *this;
    }
    void swap(string& s) {
        std::swap(_str, s._str);
        std::swap(_size, s._size);
        std::swap(_capacity, s._capacity);
    }
    ~string() { delete[] _str; }
private:
    char* _str = nullptr;
    size_t _size = 0;
    size_t _capacity = 0;
};
}

使用效果:

demo::string s1("hello");
demo::string s2 = s1;              // 拷貝構造
demo::string s3 = demo::string("world");  // 移動構造(臨時對象)
demo::string s4 = move(s1);        // 移動構造(顯式move)

編譯器還會進一步優(yōu)化。在VS2022的release模式下,demo::string s3 = demo::string("world");可能直接被優(yōu)化成一次原地構造,移動構造都不會調用——這就是返回值優(yōu)化(RVO)。

返回值場景中,如果提供了移動構造,沒有優(yōu)化時編譯器會優(yōu)先選擇移動而不是拷貝,顯著提高效率。

4. 移動語義在容器中的應用

C++11之后,STL容器的push_back、insert都增加了右值引用版本:

void push_back(const T& x);   // 左值版本,內(nèi)部拷貝
void push_back(T&& x);        // 右值版本,內(nèi)部移動

當傳入左值,走拷貝;傳入右值,走移動。

list<demo::string> lt;
demo::string s1("hello");
lt.push_back(s1);                          // 拷貝
lt.push_back(move(s1));                    // 移動
lt.push_back("world");                     // 移動(臨時string)
lt.push_back(demo::string("world"));       // 移動

自定義容器也可以實現(xiàn)相應的重載,內(nèi)部在節(jié)點構造時用move把參數(shù)轉成右值。

5. 完美轉發(fā)與引用折疊

考慮一個模板函數(shù),想要把參數(shù)原樣轉發(fā)給另一個函數(shù):

template<class T>
void relay(T&& t) {
    func(t);  // t是左值,永遠調用func的左值版本,即使傳進來的是右值
}

問題在于:t作為右值引用變量,表達式屬性是左值,所以func(t)調不到右值重載版本。要保留參數(shù)的原始值類別,需要完美轉發(fā)

template<class T>
void relay(T&& t) {
    func(forward<T>(t));
}

forward的實現(xiàn)依賴于引用折疊規(guī)則。C++不允許直接定義引用的引用(int& &),但在模板和類型推導中可以出現(xiàn)。規(guī)則只有一條:右值引用的右值引用折疊成右值引用,其余全部折疊成左值引用。

typedef int&  lref;
typedef int&& rref;
lref&  r1 = n;  // int&  &  → int&
lref&& r2 = n;  // int&  && → int&
rref&  r3 = n;  // int&& &  → int&
rref&& r4 = 1;  // int&& && → int&&

relay中,T的推導結果配合引用折疊,實現(xiàn)了“左值傳左值,右值傳右值”:

  • 實參是左值 int a → T推導為int& → T&&折疊為int&
  • 實參是右值 10 → T推導為int → T&&int&&

forward內(nèi)部也是通過static_cast<T&&>實現(xiàn)的,配合引用折疊,左值情況返回左值引用,右值情況返回右值引用。這樣就把參數(shù)的原始屬性一路傳下去了。

6. 默認移動構造與移動賦值

編譯器在特定條件下會自動生成移動構造和移動賦值:

  • 如果用戶沒有定義拷貝構造、拷貝賦值、析構函數(shù)中的任何一個,編譯器會嘗試自動生成移動構造和移動賦值。
  • 對于內(nèi)置類型成員,逐字節(jié)拷貝;對于自定義類型成員,如果能移動就移動,否則拷貝。

一旦你提供了移動構造或移動賦值,編譯器就不會自動生成拷貝構造和拷貝賦值。所以如果你想兩者都有,需要自己顯式聲明,或者用= default

class Person {
public:
    Person(const Person&) = default;   // 顯式要拷貝
    Person(Person&&) = default;        // 顯式要移動
};

也可以用= delete禁止某個函數(shù)。

移動語義是C++11最核心的特性之一。它讓“快”從“避免拷貝”的編碼技巧,變成了語言級別的優(yōu)化路徑。

到此這篇關于C++深入右值引用之移動語義與完美轉發(fā)(最新推薦)的文章就介紹到這了,更多相關C++右值引用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • C語言數(shù)組棧實現(xiàn)模板

    C語言數(shù)組棧實現(xiàn)模板

    這篇文章主要為大家詳細介紹了C語言數(shù)組棧實現(xiàn)模板,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • Qt實現(xiàn)簡易QQ聊天界面

    Qt實現(xiàn)簡易QQ聊天界面

    這篇文章主要為大家詳細介紹了Qt實現(xiàn)簡易QQ聊天界面,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • 淺析C語言中strtol()函數(shù)與strtoul()函數(shù)的用法

    淺析C語言中strtol()函數(shù)與strtoul()函數(shù)的用法

    這篇文章主要介紹了淺析C語言中strtol()函數(shù)與strtoul()函數(shù)的用法,注意其將字符串轉換成long型的區(qū)別,需要的朋友可以參考下
    2015-08-08
  • C語言數(shù)組超詳細講解中篇三子棋

    C語言數(shù)組超詳細講解中篇三子棋

    數(shù)組是一組有序的數(shù)據(jù)的集合,本篇將帶你結合數(shù)組來實現(xiàn)三子棋小游戲,上手實練更快的能夠掌握數(shù)組使用,感興趣的朋友來看看吧
    2022-04-04
  • C++中臨時對象的常見產(chǎn)生情況及其解決的方案

    C++中臨時對象的常見產(chǎn)生情況及其解決的方案

    這篇文章主要是探討常見的臨時對象產(chǎn)生的情況,及其如何避免和解決這種臨時對象產(chǎn)生的方式。具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • VCPKG安裝和使用教程(經(jīng)驗總結)

    VCPKG安裝和使用教程(經(jīng)驗總結)

    這篇文章主要介紹了VCPKG安裝和使用教程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-01-01
  • 帶你粗略了解C++中的深淺拷貝

    帶你粗略了解C++中的深淺拷貝

    這篇文章主要給大家介紹了關于c++中深淺拷貝以及寫時拷貝實現(xiàn)的相關資料,文中通過示例代碼介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面跟著小編來一起學習學習吧
    2021-08-08
  • C語言中strlen() strcpy() strcat() strcmp()函數(shù)的實現(xiàn)方法

    C語言中strlen() strcpy() strcat() strcmp()函數(shù)的實現(xiàn)方法

    這篇文章主要介紹了C語言中strlen() strcpy() strcat() strcmp()函數(shù)的實現(xiàn)方法,需要的朋友可以參考下
    2017-08-08
  • C++實現(xiàn)簡易貪吃蛇游戲

    C++實現(xiàn)簡易貪吃蛇游戲

    這篇文章主要為大家詳細介紹了C++實現(xiàn)簡易貪吃蛇游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • vs2019創(chuàng)建dll以及使用的圖文教程

    vs2019創(chuàng)建dll以及使用的圖文教程

    本文主要介紹了vs2019創(chuàng)建dll以及使用的圖文教程,文中通過圖文介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-07-07

最新評論

金乡县| 正宁县| 改则县| 黑水县| 康平县| 钟祥市| 高唐县| 南乐县| 建平县| 高淳县| 集安市| 高尔夫| 天祝| 喜德县| 遂宁市| 新建县| 玛纳斯县| 满洲里市| 察隅县| 扎鲁特旗| 江安县| 深州市| 宣恩县| 西青区| 雅安市| 沙田区| 兰考县| 铜梁县| 吴忠市| 高密市| 枣阳市| 宣恩县| 宜阳县| 石门县| 太康县| 平度市| 乐平市| 南安市| 长丰县| 长海县| 库车县|