“複製賦值”和“移動賦值”的思考

來源:互聯網
上載者:User

標籤:img   調用   swa   copy   using   struct   使用   span   分享   

概述

從 C++ 11 中開始,該語言支援兩種類型的分配:複製賦值移動賦值。其中的內部細節是咋樣的呢?今天跟蹤了一下,是個蠻有趣的過程。下面我們以一個簡單的類來做個分析。

#ifndef HASPTR_H#define HASPTR_H#include <string>class HasPtr {public:    friend void swap(HasPtr&, HasPtr&);    HasPtr(const std::string& s = std::string());    HasPtr(const HasPtr& hp);    HasPtr(HasPtr&& p) noexcept;    HasPtr& operator=(HasPtr rhs);    // HasPtr& operator=(const HasPtr &rhs);    // HasPtr& operator=(HasPtr &&rhs) noexcept;    ~HasPtr();private:    std::string* ps;    int i;};#endif // HASPTR_H#include "hasptr.h"#include <iostream>inline void swap(HasPtr& lhs, HasPtr& rhs){    using std::swap;    swap(lhs.ps, rhs.ps);    swap(lhs.i, rhs.i);    std::cout << "call swap" << std::endl;}HasPtr::HasPtr(const std::string& s) : ps(new std::string(s)), i(){    std::cout << "call constructor" << std::endl;}//這裡的i+1隻是為了方便調試的時候看過程,實際是不用加1的HasPtr::HasPtr(const HasPtr& hp) : ps(new std::string(*hp.ps)), i(hp.i + 1){    std::cout << "call copy constructor" << std::endl;}HasPtr::HasPtr(HasPtr&& p) noexcept : ps(p.ps), i(p.i){    p.ps = 0;    std::cout << "call move constructor" << std::endl;}HasPtr& HasPtr::operator=(HasPtr rhs){    swap(*this, rhs);    return *this;}HasPtr::~HasPtr(){    std::cout << "call destructor" << std::endl;    delete ps;}

主函數

int main(int argc, char *argv[]){    QCoreApplication a(argc, argv);    HasPtr hp1("hello"), hp2("World"), *pH = new HasPtr("World");    hp1 = hp2;    hp1 = std::move(*pH);    return a.exec();}

下面我們開始調試:

輸出:

我們通過建構函式構造了三個變數,他們的值和

  address ps i
hp1 0x28fe64 "hello" 0
hp2 0x28fe5c "World" 0
pH 0x28fe9c "World" 0

 

 

 複製賦值

我們接著單步走:

可以發現首先調用了複製建構函式,構造了一個和hp2一樣的臨時變數

  address ps i
this 0x28fe2c "World" 1
hp2 0x28fe5c "World" 0

 

 

 

下一步:

到這裡才開始進行賦值運算,我們對比一下資料:

  address ps i
this 0x28fe2c "hello" 0
rhs 0x28fe8c "World" 1

 

 

 

這裡的rhs就是我們剛剛分配的臨時變數,那麼this就是hp1,所以最終是我們的臨時變數和hp1交換,我們接著走:

這裡lhs的地址就是:0x28fe64,就是hp1的地址,交換之後:

到此hp1和臨時變數的值就完全交換過來了,也就是說hp1 = hp1了。

  address ps i
lhs 0x28fe64 "World" 1
rhs 0x28fe8c "hello" 0

 

 

 

 

可是我們接著運行,發現進入了一個解構函式:

 

看一下地址是0x28fe8c以及其值,這是臨時變數,臨時變數不用了,所以被銷毀了,至此我們的複製賦值運算就結束了。

移動賦值

我們看一下移動賦值賦值:

 

首先進入移動函數,這裡只是使指標指向了pH的資料,並未構造新的資料,變數右值引用了pH,只是相當於換了個名字。

接下來開始進入賦值運算:

 

這裡兩個交換的值是hp1和pH,和複製賦值不同,它是和臨時變數交換資料,

 

後面進入解構函式:

它釋放掉了pH的資料。

 

可以看出來,pH的值被釋放掉了。

總結

調試過後,我們發現,賦值運算的過程並非像想象中那麼簡單,是不是?複製賦值還是開闢一個臨時變數用於轉化,這個耗費了額外的空間資源。

移動賦值就可以避免這個問題,但是需要注意的是,移動賦值使用的是右值,用完之後就被銷毀了,所以,如果想把一個左值當做右值來用,必須確保這個左值在這之後不需要使用了。

 參考:

  1.   《C++ primer》

“複製賦值”和“移動賦值”的思考

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.