欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解C++中移動語義的概念與使用

 更新時間:2023年06月09日 08:42:24   作者:ENG八戒  
本篇文章主要為大家詳細介紹了C++中移動語義的相關(guān)知識,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考,一起跟隨小編過來看看吧

過去寫 C/C++ 代碼,大家對數(shù)據(jù)做傳遞時,都習(xí)慣先拷貝再賦值。比如,把數(shù)據(jù)從 t1 復(fù)制到 t2,復(fù)制完成后 t2 和 t1 的狀態(tài)是一致的,t1 狀態(tài)沒變。這里的狀態(tài)指的是對象內(nèi)部的非靜態(tài)成員數(shù)據(jù)集合。

在程序運行過程中,復(fù)制過程既要分配空間又要拷貝內(nèi)容,對于空間和時間都是種損耗。復(fù)制操作,無疑是一門很大的開銷,何況經(jīng)常觸發(fā)資源復(fù)制的時候。

來看看普通的函數(shù)返回值到底有哪些開銷,

std::string getString()
{
    std::string s;
    // ...

    return s;
}

int main()
{
    std::string str = getString();
    // ...
}

假設(shè)你的編譯器還不支持 C++ 11,那么,在 main() 函數(shù)里調(diào)用 getString() 時,需要在調(diào)用棧里分配臨時對象用于復(fù)制 getString() 的返回值 s,復(fù)制完成調(diào)用 s 的析構(gòu)函數(shù)釋放對象。然后,再調(diào)用 std::string 類的復(fù)制賦值運算符函數(shù)將臨時對象復(fù)制到 str,同時調(diào)用臨時對象的析構(gòu)函數(shù)執(zhí)行釋放。

那么,有沒有技巧可以實現(xiàn)上面示例代碼同樣的效果,同時避免復(fù)制?

有的,就是接下來重點介紹的移動(和中國移動無關(guān))。

相對于復(fù)制,移動無須重新分配空間和拷貝內(nèi)容,只需把源對象的數(shù)據(jù)重新分配給目標(biāo)對象即可。移動后目標(biāo)對象狀態(tài)與移動前的源對象狀態(tài)一致,但是移動后源對象狀態(tài)被清空。

實際上,大部份的情況下,數(shù)據(jù)僅僅需要移動即可,拷貝復(fù)制顯得多余。就像,你從圖書館借書,把自己手機的 SIM 卡拔出來再插到其它手機上,去商店買東西你的錢從口袋移動到收銀柜等等。

那么,是不是可以對所有的數(shù)據(jù)都執(zhí)行移動?

答案是否定的。在現(xiàn)代 C++ 中,只有右值可以被移動。

左右值概念

在 C++ 11 之前,左右值的劃分比較簡單,只有左值和右值兩種。

但是從 C++ 11 開始,重新把值類別劃分成了五種,左值(lvalue, left value),將亡值(xvalue, expiring value),純右值(prvalue, pure right value),泛左值(glvalue, generalized left value),右值(rvalue, right value)。不過后邊的兩種 glvalue 和 rvalue 是基于前面的三種組合而成。從集合概念來看,glvalue 包含 lvalue 和 xvalue,rvalue 包含 xvalue 和 prvalue。

左右值劃分的依據(jù)是:具名和可被移動。

具名,簡單點理解就是尋址??杀灰苿?,允許對量的內(nèi)部資源移動到其它位置,并且保持量自身是有效的,但是狀態(tài)不確定。

  • lvalue:具名且不可移動
  • xvalue:具名且可移動
  • prvalue:不具名且可移動

那么,可以看到泛左值(glvalue)其實就是具名的量,右值就是可移動的量。

以往在往函數(shù)傳參的時候,經(jīng)常有用到值引用的模式,形式如下:

function(T& obj)

T 是類型,obj 是參數(shù)。

到了現(xiàn)代 C++,原來的值引用就變成了左值引用,另外還出現(xiàn)了右值引用,形式如下:

function(T&& obj)

那么 C++ 11 是怎樣實現(xiàn)移動操作的呢?

實現(xiàn)移動操作

移動操作依賴于類內(nèi)部特殊成員函數(shù)的執(zhí)行,但前提是該對象是可移動的。如果恰好對象是左值(lvalue)呢?

C++ 11 的標(biāo)準(zhǔn)庫就提供了 std::move() 實現(xiàn)左右值轉(zhuǎn)換操作。std::move() 用于將表達式從 lvalue(左值) 轉(zhuǎn)換成 xvalue(將亡值),但不會對數(shù)值執(zhí)行移動。當(dāng)然,使用強制類型轉(zhuǎn)換也是可以達到同樣目的。

std::move(obj); // 等價于 static_cast<T&&>(obj);

在 stack overflow 上看到對 std::move() 的一段描述,與其說它是一個函數(shù),不如說,它是編譯器對表達式值評估的方式轉(zhuǎn)換器。

以往慣常使用 C++ 類定義時,我們都知道有這么幾個特殊的成員函數(shù):

  • 默認構(gòu)造函數(shù)(default constructor)
  • 復(fù)制構(gòu)造函數(shù)(copy constructor)
  • 復(fù)制賦值運算符函數(shù)(copy assignment operator)
  • 析構(gòu)函數(shù)(destructor)

來看看一個簡單的例子:

class MB // MemoryBlock
{
public:
    // 為下面代碼演示簡單起見
    // 在 public 定義成員屬性
    size_t size;
    char *buf;

    // 默認構(gòu)造函數(shù)
    explicit MB(int sz = 1024)
        : size(sz), buf(new char[sz]) {}
    // 析構(gòu)函數(shù)
    ~MB() {
        if (buf != nullptr) {
            delete[] buf;
        }
    }
    // 復(fù)制構(gòu)造函數(shù)
    MB(const MB& obj)
        : size(obj.size),
          buf(new char[obj.size]) {
        memcpy(buf, obj.buf, size);
    }
    // 復(fù)制賦值運算符函數(shù)
    MB& operator=(const MB& obj) {
        if (this != &obj) {
            if (buf != nullptr) {
                delete[] buf;
            }
            size = obj.size;
            buf = new char[size]; 
            memcpy(buf, obj.buf, size);
        }
        return *this;
    }
}

為了支持移動操作,從 C++ 11 開始,類定義里新增了兩個特殊成員函數(shù):

  • 移動構(gòu)造函數(shù)(move constructor)
  • 移動賦值運算符函數(shù)(move assignment operator)

移動構(gòu)造函數(shù)

在構(gòu)造新對象時,如果傳入的參數(shù)是右值引用對象,就會調(diào)用移動構(gòu)造函數(shù)創(chuàng)建對象。如果沒有自定義移動構(gòu)造函數(shù),那么編譯器就會自動生成,默認實現(xiàn)是遍歷調(diào)用成員屬性的移動構(gòu)造函數(shù),并移動右值對象的成員屬性數(shù)據(jù)到新對象。

定義一般聲明形式如下:

T::T(C&& other);

基于上面的簡單例子:

class MB // MemoryBlock
{
public:
    // ...

    // 移動構(gòu)造函數(shù)
    MB(MB&& obj)
        : size(0), buf(nullptr) {
        // 移動源對象數(shù)據(jù)到新對象
        size = obj.size;
        buf = obj.buf;
        // 清空源對象狀態(tài)
        // 避免析構(gòu)函數(shù)多次釋放資源
        obj.size = 0;
        obj.buf = nullptr;
    }
}

可見,移動構(gòu)造函數(shù)的執(zhí)行過程,僅僅是簡單賦值的過程,不涉及拷貝資源的耗時操作,自然執(zhí)行效率大大提高。

移動賦值運算符函數(shù)

在調(diào)用賦值運算符時,如果右邊傳入的參數(shù)是右值引用對象,就會調(diào)用移動賦值運算符函數(shù)。同樣,如果沒有自定義移動賦值運算符函數(shù),那么編譯器也會自動生成,默認實現(xiàn)是遍歷調(diào)用成員屬性的移動賦值運算符函數(shù)并移動成員屬性的數(shù)據(jù)到左邊參數(shù)對象。

一般聲明形式如下:

T& T::operator=(C&& other);

基于上面的簡單例子:

class MB // MemoryBlock
{
public:
    // ...
    // 移動賦值運算符函數(shù)
    MB& MB::operator=(MB&& obj) {
        if (this != &obj) {
            if (buf != nullptr) {
                delete[] buf;
            }
            // 移動源對象數(shù)據(jù)到新對象
            size = obj.size;
            buf = obj.buf;
            // 清空源對象狀態(tài)
            // 避免析構(gòu)函數(shù)多次釋放資源
            obj.size = 0;
            obj.buf = nullptr;
        }
        return *this;
    }
}

移動賦值運算符函數(shù)的執(zhí)行過程,同樣僅僅是簡單賦值的過程,執(zhí)行效率明顯遠超復(fù)制操作。

總結(jié)

回顧文首的示例代碼,由于 C++ 11 加入了返回值優(yōu)化 RVO(Return Value Optimization) 的特性,所以代碼無需變更即可獲得效率提升。對于部分編譯器而言,比如 IBM Compiler、Visual C++ 2010 等,已經(jīng)提前具備返回值優(yōu)化的支持。

到此這篇關(guān)于詳解C++中移動語義的概念與使用的文章就介紹到這了,更多相關(guān)C++移動語義內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++20中std::format的示例代碼

    C++20中std::format的示例代碼

    本文詳細介紹了C++20中std::format的功能、使用方法和高級應(yīng)用,包括基本用法、數(shù)字和文本的格式化、日期和時間的處理、自定義類型的格式化等,感興趣的可以了解一下
    2024-10-10
  • 聊聊C語言中sizeof運算符的一個陷阱

    聊聊C語言中sizeof運算符的一個陷阱

    在C語言中,sizeof()是一個判斷數(shù)據(jù)類型或者表達式長度的運算符,下面這篇文章主要給大家介紹了關(guān)于C語言中sizeof運算符的一個陷阱的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-11-11
  • C語言 詳細解析時間復(fù)雜度與空間復(fù)雜度

    C語言 詳細解析時間復(fù)雜度與空間復(fù)雜度

    算法復(fù)雜度分為時間復(fù)雜度和空間復(fù)雜度。其作用: 時間復(fù)雜度是度量算法執(zhí)行的時間長短;而空間復(fù)雜度是度量算法所需存儲空間的大小
    2022-04-04
  • C++變位詞問題分析

    C++變位詞問題分析

    這篇文章主要介紹了C++變位詞問題分析,非常經(jīng)典的算法,對于進行C++下的算法設(shè)計有很大的啟發(fā)性,需要的朋友可以參考下
    2014-08-08
  • C++對Json數(shù)據(jù)的友好處理實現(xiàn)過程

    C++對Json數(shù)據(jù)的友好處理實現(xiàn)過程

    在Ajax的應(yīng)用中,前臺基本上會用到JSON作為數(shù)據(jù)交換格式,所以下面這篇文章主要給大家介紹了關(guān)于C++對Json數(shù)據(jù)的友好處理,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-02-02
  • C++使用異或運算實現(xiàn)交換兩個數(shù)的值

    C++使用異或運算實現(xiàn)交換兩個數(shù)的值

    交換兩個數(shù)的值,通常用利用一個變量來交換數(shù)值,異或交換兩個數(shù)的值是資源開銷最小的方法,不需要中介數(shù),原理簡單的來說就是異或的負負得正
    2018-09-09
  • C語言去除相鄰重復(fù)字符函數(shù)的實現(xiàn)方法

    C語言去除相鄰重復(fù)字符函數(shù)的實現(xiàn)方法

    這篇文章主要介紹了C語言去除相鄰重復(fù)字符函數(shù)的實現(xiàn)方法的相關(guān)資料,實現(xiàn)去重字符串相鄰重復(fù)的字符,不相鄰的不用去重的功能,需要的朋友可以參考下
    2017-08-08
  • c++中的消息框messagebox()詳細介紹及使用方法

    c++中的消息框messagebox()詳細介紹及使用方法

    本文將介紹下c++中的messagebox()的使用方法:常用屬性/按鈕的形式/返回值等等,感興趣的朋友可以了解下,希望本文可以幫助到你
    2013-02-02
  • c語言同名標(biāo)靶點自動匹配算法實現(xiàn)實例代碼

    c語言同名標(biāo)靶點自動匹配算法實現(xiàn)實例代碼

    這篇文章主要介紹了c語言同名標(biāo)靶點自動匹配算法實現(xiàn)實例代碼,分享了相關(guān)代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下
    2018-02-02
  • C++11的新特性簡單匯總介紹 (二)

    C++11的新特性簡單匯總介紹 (二)

    最近學(xué)習(xí)了C++11的新特性,將學(xué)習(xí)內(nèi)容整理下來以鞏固記憶,這里分享給大家,希望對大家學(xué)習(xí)C++11能夠有所幫助
    2016-07-07

最新評論