1. 程式人生 > 實用技巧 >[C++] 右值引用

[C++] 右值引用

#include <iostream>
#include <cstring>
using namespace std;

class A {
public:
    char *p;
    A() {
        p = new char[3];
    };

    A(const A& a) {
        p  = new char[3];
        for(int i = 0; i < 3; ++i) {
            p[i] = a.p[i];
        }
    }
    
    // 移動構造
    A(A&& a) {
        cout 
<< "in move constructor" << endl; p = a.p; a.p = nullptr; } // 移動賦值 A& operator=(A&& a) { cout << "in move = operator" << endl; p = a.p; a.p = nullptr; return *this; } ~A() {}; }; int main() {
/** 1. 對基礎型別變數(如int)進行move操作, move前後的變數(i, rr)指向了同一塊記憶體空間; 如下例 (1) int &&rr = move(i); 之後i, rr對應同一塊記憶體,值均為22; (2) i = 44; 之後,i,rr的值均為44 */ int i = 22; int &&rr = move(i); cout << "ori i = 22, move to rr" << endl; cout << "
i = " << i << endl; // 22 cout << "rr = " << rr << endl; // 22 cout << endl; cout << "after i = 44" << endl; i = 44; cout << "i = " << i << endl; // 44 cout << "rr = " << rr << endl; // 44 cout << endl; /** 2. 對含有指標的類進行move操作 (1) 為什麼需要move 類中如果含有指標,那麼對類物件在進行拷貝時,要思考進行深拷貝還是淺拷貝; 如果進行淺拷貝,對於類中的指標型別,只能copy指標的地址,並不能複製指標指向的內容; 如果進行深拷貝,對於類中的指標型別,則重新開闢了一塊記憶體空間,copy指標指向的內容; 但是對於一些被copy之後不會再被用到的類物件,卻還佔據著空間, 於是希望引入"move",把原物件的記憶體"偷"過來,接管對原物件記憶體空間的管理權, 以達到節約開銷,提高效能的目的; (2) 如何move 對於類中的指標,在呼叫時一般是不可見的(如private型別的), 所以需要類的構造者在設計建構函式時,考慮如果將其進行拷貝or賦值操作時應如何處理指標。 對於move操作,有移動構造和移動賦值2種; 移動構造:在宣告定義時進行初始化;見class A中的 A(A&& a) 移動賦值:用=賦值;見class A 中的 A& operator=(A&& a) 如果使用move,開發者要設計好類中的以上2中操作,一般是: 再建立一個新的指標, 用新指標地址 = 被複制物件的對應指標地址, 將被複制物件的對應指標 指向 設定為空。 */

A a; char *s = "ab"; a.p = s; cout << "a.p = " << endl; for(int i = 0; i < 3; ++i) { // 這裡轉int可以看到字串是否以\0結束 cout << int(a.p[i]) << " "; // 97 98 0 } cout << endl; /////// 1. 普通的拷貝構造 ////////// A b(a); cout << "b.p = " << endl; for(int i = 0; i < 3; ++i) { cout << b.p[i] << " "; // a b } cout << endl; cout << endl; /////// 2. 移動賦值 c = move(a); ////////// // 這裡將 char* 強轉 int* 為了獲取指標p的地址 // 如果不強轉, C++在對char*輸出時,會預設輸出指標所指向地址的值(ex."ab") // 下例輸出: // in move = operator // after A c = move(a) // a.p = 0x0 // c.p = 0x10e3d0edb A c; c = move(a); cout << "after A c = move(a)" << endl; cout << "a.p = " << (int*)a.p << endl; cout << "c.p = " << (int*)c.p << endl; /////// 3. 移動構造 A e(move(d)); ////////// // in move constructor // after e(move(d)) // d.p = 0x0 // e.p = 0x10e3d0f09 A d; char *s2 = "cd"; d.p = s2; A e(move(d)); cout << "after e(move(d))" << endl; cout << "d.p = " << (int*)d.p << endl; cout << "e.p = " << (int*)e.p << endl; return 0; }