青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

羅朝輝(飄飄白云)

關注嵌入式操作系統,移動平臺,圖形開發。-->加微博 ^_^

  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
  85 隨筆 :: 0 文章 :: 169 評論 :: 0 Trackbacks

【譯】VC10中的C++0x特性 part 2(2):右值引用

來源:vcblog 作者:Stephan T. Lavavej 翻譯:飄飄白云  

 

(轉載時請注明作者和出處。未經許可,請勿用于商業用途)

簡介

這一系列文章介紹Microsoft Visual Studio 2010 中支持的C++ 0x特性,目前有三部分。
Part 1 :介紹了Lambdas, 賦予新意義的auto,以及 static_assert;
Part 2( , , ):介紹了右值引用(Rvalue References);
Part 3:介紹了表達式類型(decltype)

VC10中的C++0x特性 Part 1,2,3 譯文打包下載(doc 和 pdf 格式): 點此下載


本文為 Part 2 第二頁。


move 語意:從 lvalue 移動


現在,如果你喜歡用拷貝賦值函數來實現你的拷貝構造函數該怎樣做呢,那你也可能試圖用 move 拷貝賦值函數來實現 move 構造函數。這樣作是可以的,但是你得小心。下面就是一個錯誤的實現:

 

C:\Temp>type unified_wrong.cpp

#include <stddef.h>

#include <iostream>

#include <ostream>

using namespace std;

 

class remote_integer {

public:

    remote_integer() {

        cout << "Default constructor." << endl;

 

        m_p = NULL;

    }

 

    explicit remote_integer(const int n) {

        cout << "Unary constructor." << endl;

 

        m_p = new int(n);

    }

 

    remote_integer(const remote_integer& other) {

        cout << "Copy constructor." << endl;

 

        m_p = NULL;

        *this = other;

    }

 

#ifdef MOVABLE

    remote_integer(remote_integer&& other) {

        cout << "MOVE CONSTRUCTOR." << endl;

 

        m_p = NULL;

        *this = other; // WRONG

    }

#endif // #ifdef MOVABLE

 

    remote_integer& operator=(const remote_integer& other) {

        cout << "Copy assignment operator." << endl;

 

        if (this != &other) {

            delete m_p;

 

            if (other.m_p) {

                m_p = new int(*other.m_p);

            } else {

                m_p = NULL;

            }

        }

 

        return *this;

    }

 

#ifdef MOVABLE

    remote_integer& operator=(remote_integer&& other) {

        cout << "MOVE ASSIGNMENT OPERATOR." << endl;

 

        if (this != &other) {

            delete m_p;

 

            m_p = other.m_p;

            other.m_p = NULL;

        }

 

        return *this;

    }

#endif // #ifdef MOVABLE

 

    ~remote_integer() {

        cout << "Destructor." << endl;

 

        delete m_p;

    }

 

    int get() const {

        return m_p ? *m_p : 0;

    }

 

private:

    int * m_p;

};

 

remote_integer frumple(const int n) {

    if (n == 1729) {

        return remote_integer(1729);

    }

 

    remote_integer ret(n * n);

 

    return ret;

}

 

int main() {

    remote_integer x = frumple(5);

 

    cout << x.get() << endl;

 

    remote_integer y = frumple(1729);

 

    cout << y.get() << endl;

}

 

C:\Temp>cl /EHsc /nologo /W4 /O2 unified_wrong.cpp

unified_wrong.cpp

 

C:\Temp>unified_wrong

Unary constructor.

Copy constructor.

Copy assignment operator.

Destructor.

25

Unary constructor.

1729

Destructor.

Destructor.

 

C:\Temp>cl /EHsc /nologo /W4 /O2 /DMOVABLE unified_wrong.cpp

unified_wrong.cpp

 

C:\Temp>unified_wrong

Unary constructor.

MOVE CONSTRUCTOR.

Copy assignment operator.

Destructor.

25

Unary constructor.

1729

Destructor.

Destructor.

 

(編譯器在這里進行了返回值優化(RVO),但不是具名返回值優化(NRVO)。就像我之前提到的,有些拷貝構造函數被 RVO 或 NRVO 優化掉了,但編譯器并不總是能夠做這樣的優化,這時剩余的就由 move 構造函數來優化。)

 

move 構造函數中標記為 WRONG 的那一行,調用了拷貝賦值函數,編譯能通過也能運行,但這違背了 move 構造函數的本意。(譯注:因為那個拷貝賦值函數只是進行普通的拷貝賦值,而不是 move 賦值!)

 

這是怎么回事呢?記住:在C++98/03中,具名 lvalue 引用是左值(給定語句 int& r = *p; r 是 lvalue),不具名 lvalue 引用還是左值(給定語句 vector<int> v(10, 1729), v[0] 返回 int&, 你可以對這個不具名 lvalue 引用取址)。但是 rvalue 引用就不一樣了:

 

? 具名 lvalue 引用是 lvalue

? 不具名 rvalue 引用是 rvalue

 

一個具名 rvalue 引用是一個 lvalue 是因為可以對它施加多重操作,重復使用。相反,如果它是一個 ravlue 的話,那么對它施加的第一個操作能夠“竊取”它,而后續操作就沒機會了。這里的“竊取”是說不會被察覺到,所以這是行不通的。另一方面,不具名 rvalue 引用不能被重復使用,所以它仍保持右值(rvalueness)語意。

 

如果你真的打算用 move 賦值函數來實現 move 構造函數,你需要從 lvalue move,就像是從 rvalue move 一樣。C++0x <utility> 中的 std::move() 具備這樣的能力,VC10將會有這個(實際上,開發版中已經有了),但VC10 TCP版還沒有,所以我會教你從頭做起:

 

C:\Temp>type unified_right.cpp

#include <stddef.h>

#include <iostream>

#include <ostream>

using namespace std;

 

template <typename T> struct RemoveReference {

     typedef T type;

};

 

template <typename T> struct RemoveReference<T&> {

     typedef T type;

};

 

template <typename T> struct RemoveReference<T&&> {

     typedef T type;

};

 

template <typename T> typename RemoveReference<T>::type&& Move(T&& t) {

    return t;

}

 

class remote_integer {

public:

    remote_integer() {

        cout << "Default constructor." << endl;

 

        m_p = NULL;

    }

 

    explicit remote_integer(const int n) {

        cout << "Unary constructor." << endl;

 

        m_p = new int(n);

    }

 

    remote_integer(const remote_integer& other) {

        cout << "Copy constructor." << endl;

 

        m_p = NULL;

        *this = other;

    }

 

#ifdef MOVABLE

    remote_integer(remote_integer&& other) {

        cout << "MOVE CONSTRUCTOR." << endl;

 

        m_p = NULL;

        *this = Move(other); // RIGHT

    }

#endif // #ifdef MOVABLE

 

    remote_integer& operator=(const remote_integer& other) {

        cout << "Copy assignment operator." << endl;

 

        if (this != &other) {

            delete m_p;

 

            if (other.m_p) {

                m_p = new int(*other.m_p);

            } else {

                m_p = NULL;

            }

        }

 

        return *this;

    }

 

#ifdef MOVABLE

    remote_integer& operator=(remote_integer&& other) {

        cout << "MOVE ASSIGNMENT OPERATOR." << endl;

 

        if (this != &other) {

            delete m_p;

 

            m_p = other.m_p;

            other.m_p = NULL;

        }

 

        return *this;

    }

#endif // #ifdef MOVABLE

 

    ~remote_integer() {

        cout << "Destructor." << endl;

 

        delete m_p;

    }

 

    int get() const {

        return m_p ? *m_p : 0;

    }

 

private:

    int * m_p;

};

 

remote_integer frumple(const int n) {

    if (n == 1729) {

        return remote_integer(1729);

    }

 

    remote_integer ret(n * n);

 

    return ret;

}

 

int main() {

    remote_integer x = frumple(5);

 

    cout << x.get() << endl;

 

    remote_integer y = frumple(1729);

 

    cout << y.get() << endl;

}

 

C:\Temp>cl /EHsc /nologo /W4 /O2 /DMOVABLE unified_right.cpp

unified_right.cpp

 

C:\Temp>unified_right

Unary constructor.

MOVE CONSTRUCTOR.

MOVE ASSIGNMENT OPERATOR.

Destructor.

25

Unary constructor.

1729

Destructor.

Destructor.

 

(我將交替使用 std::move() 和我自己的 Move(),因為它們的實現是等價的) std::move() 是怎樣工作的呢?目前,我只能跟你說這是“魔法”。(后面會有完整的解釋,并不復雜,但它與模板參數推導和引用折疊(reference collapsing,譯注:引用的引用)有 關,后面講完美轉發的時候我們還會遇到這兩個東西)。我可以用一個具體的例子來略過“魔法”:給定一個 string 類型的左值,像前面重載決議例子中的 up ,std::move(up) 調用 string&& std::move(string&),這個函數返回一個不具名的 rvalue 引用,它是一個 rvalue。給定一個 string 類型的 rvalue,像前面重載決議例子中的 strange(), std::move(strange()) 調用 string&& std::move(string&&),同樣這個函數還是返回一個不具名的 rvalue,還是 rvalue。

 

std::move() 除了讓你能用 move 復制函數來實現 move 構造函數之外,還能在其他地方發揮作用。無論何時,只要你有一個左值,而它的值也不再重要了(例如,它將被銷毀或被賦值),你就可以使用 std::move(你的左值表達式) 來使用 move 語意。

 

move 語意:可移動成員(movable member)


C++0x 的標準類型(像 vector, string, regex) 都有 move 構造函數和 move 賦值函數。而且我們也已經看到了如何在我們自己的類中通過手動管理資源來實現 move 語意(像前面的 remote_integer 類)。如果類中包含可移動數據成員(像 vector, string, regex, remote_integer )時該怎么辦呢?編譯器不會自動幫我們自動產生 move 構造函數和 move 賦值函數,所以我們必須手動編寫它們。很幸運,有了 std::move() 編寫它們是很容易的。

 

C:\Temp>type point.cpp

#include <stddef.h>

#include <iostream>

#include <ostream>

using namespace std;

 

template <typename T> struct RemoveReference {

     typedef T type;

};

 

template <typename T> struct RemoveReference<T&> {

     typedef T type;

};

 

template <typename T> struct RemoveReference<T&&> {

     typedef T type;

};

 

template <typename T> typename RemoveReference<T>::type&& Move(T&& t) {

    return t;

}

 

class remote_integer {

public:

    remote_integer() {

        cout << "Default constructor." << endl;

 

        m_p = NULL;

    }

 

    explicit remote_integer(const int n) {

        cout << "Unary constructor." << endl;

 

        m_p = new int(n);

    }

 

    remote_integer(const remote_integer& other) {

        cout << "Copy constructor." << endl;

 

        if (other.m_p) {

            m_p = new int(*other.m_p);

        } else {

            m_p = NULL;

        }

    }

 

    remote_integer(remote_integer&& other) {

        cout << "MOVE CONSTRUCTOR." << endl;

 

        m_p = other.m_p;

        other.m_p = NULL;

    }

 

    remote_integer& operator=(const remote_integer& other) {

        cout << "Copy assignment operator." << endl;

 

        if (this != &other) {

            delete m_p;

 

            if (other.m_p) {

                m_p = new int(*other.m_p);

            } else {

                m_p = NULL;

            }

        }

 

        return *this;

    }

 

    remote_integer& operator=(remote_integer&& other) {

        cout << "MOVE ASSIGNMENT OPERATOR." << endl;

 

        if (this != &other) {

            delete m_p;

 

            m_p = other.m_p;

            other.m_p = NULL;

        }

 

        return *this;

    }

 

    ~remote_integer() {

        cout << "Destructor." << endl;

 

        delete m_p;

    }

 

    int get() const {

        return m_p ? *m_p : 0;

    }

 

private:

    int * m_p;

};

 

class remote_point {

public:

    remote_point(const int x_arg, const int y_arg)

        : m_x(x_arg), m_y(y_arg) { }

 

    remote_point(remote_point&& other)

        : m_x(Move(other.m_x)),

          m_y(Move(other.m_y)) { }

 

    remote_point& operator=(remote_point&& other) {

        m_x = Move(other.m_x);

        m_y = Move(other.m_y);

        return *this;

    }

 

    int x() const { return m_x.get(); }

    int y() const { return m_y.get(); }

 

private:

    remote_integer m_x;

    remote_integer m_y;

};

 

remote_point five_by_five() {

    return remote_point(5, 5);

}

 

remote_point taxicab(const int n) {

    if (n == 0) {

        return remote_point(1, 1728);

    }

 

    remote_point ret(729, 1000);

 

    return ret;

}

 

int main() {

    remote_point p = taxicab(43112609);

 

    cout << "(" << p.x() << ", " << p.y() << ")" << endl;

 

    p = five_by_five();

 

    cout << "(" << p.x() << ", " << p.y() << ")" << endl;

}

 

C:\Temp>cl /EHsc /nologo /W4 /O2 point.cpp

point.cpp

 

C:\Temp>point

Unary constructor.

Unary constructor.

MOVE CONSTRUCTOR.

MOVE CONSTRUCTOR.

Destructor.

Destructor.

(729, 1000)

Unary constructor.

Unary constructor.

MOVE ASSIGNMENT OPERATOR.

MOVE ASSIGNMENT OPERATOR.

Destructor.

Destructor.

(5, 5)

Destructor.

Destructor.

 

現在你看到啦,按成員移動(memberwise move)是很容易做到的。注意, remote_point 的 move 賦值函數沒有進行自我賦值檢查,是因為 remote_integer 已經檢查過了。也要注意到 remote_point 隱式聲明的拷貝構造函數,拷貝賦值函數和析構函數都正常運作。

 

到現在,你應該對 move 語意已經非常熟悉了。(希望不是抓狂啊!)為了測試你新獲得的這個不可思議的技能,請為前面的例子寫一個 +() 操作符函數當作練習吧。

 

最后的提醒:只要你的類支持 move 語意,你就應該實現 move 構造函數和 move 賦值函數。因為不僅僅是你平常使用這些類時可從 move 語意中獲利, STL 容器和算法也能從中獲利,通過廉價的 move 省下昂貴的拷貝開銷。


(轉載請注明出處,作者與譯者信息,請勿用于商業用途) 


 < 前一頁  后一頁 >


posted on 2009-06-04 09:37 羅朝輝 閱讀(2282) 評論(3)  編輯 收藏 引用 所屬分類: C/C++

評論

# re: VC10中的C++0x特性 part 2(2):右值引用[未登錄] 2009-06-04 11:27 Terry
翻譯得非常好!頂!  回復  更多評論
  

# re: VC10中的C++0x特性 part 2(2):右值引用 2009-06-05 08:20 hlysh
沒用,現在哪里開發用c++0x了?  回復  更多評論
  

# re: 【譯】VC10中的C++0x特性 part 2(2):右值引用 2009-07-23 11:28 gaojl0728
great work!  回復  更多評論
  

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲图片欧美午夜| 国产精品一级在线| 欧美国产极速在线| 国产精品一区免费视频| 亚洲黄一区二区| 欧美在线啊v一区| 欧美中文在线免费| 免费看的黄色欧美网站| 亚洲电影激情视频网站| 日韩午夜av在线| 亚洲影视在线播放| 亚洲一区二区在线| 久久先锋资源| 久久久久99精品国产片| 国产欧美91| 亚洲电影免费观看高清完整版| 国产日韩一区二区三区在线| 国产永久精品大片wwwapp| 在线免费观看日本欧美| 99精品99| 久久久国产精品亚洲一区| 欧美激情精品久久久久久黑人 | 精品99一区二区三区| 伊人蜜桃色噜噜激情综合| 一区二区三区欧美视频| 久久综合九九| 日韩亚洲欧美在线观看| 久久久久国产精品人| 亚洲人成网站精品片在线观看| 亚洲欧美日韩国产一区| 欧美日韩1区2区3区| 精品成人a区在线观看| 亚洲一区二区三区中文字幕| 免费亚洲电影在线| 亚洲一区久久久| 欧美成人精品激情在线观看| 国产综合在线看| 久久婷婷综合激情| 一区二区三区视频在线| 免费观看成人| 尤物九九久久国产精品的特点| 午夜精品久久久久久| 亚洲精品九九| 欧美韩日一区二区三区| 亚洲国产精品传媒在线观看| 久久一区视频| 欧美主播一区二区三区| 国产欧美日韩精品丝袜高跟鞋| 亚洲永久免费视频| av成人免费在线| 欧美日本不卡| 一区二区精品| 亚洲高清视频一区二区| 久久久久久久国产| 午夜精品久久久久久久久久久久久| 欧美国产日韩一二三区| 性色一区二区三区| 欧美激情中文字幕在线| 亚洲电影免费观看高清| 麻豆九一精品爱看视频在线观看免费 | 裸体一区二区| 久久精品30| 性色av一区二区三区| 久久久久久久网| 久久av在线看| 国产日韩专区在线| 香蕉久久夜色精品国产| 亚洲在线第一页| 国产日韩精品在线| 亚洲欧美精品在线观看| 中日韩美女免费视频网址在线观看| 国产精品久久久一本精品| 亚洲女人小视频在线观看| 亚洲欧美日韩国产成人| 极品少妇一区二区三区| 欧美激情日韩| 欧美日韩亚洲视频一区| 久久不见久久见免费视频1| 久久精彩免费视频| 久久久精品国产一区二区三区 | 国产精品美女主播| 久久久99精品免费观看不卡| 久久夜色精品亚洲噜噜国产mv| 亚洲国产日韩一区二区| 亚洲精品一区在线观看香蕉| 国产精品露脸自拍| 免费观看日韩av| 欧美日韩亚洲一区在线观看| 久久国产精品一区二区三区| 久久尤物视频| 亚洲一区二区三区涩| 亚洲视频狠狠| 亚洲国产高清视频| 一区二区三区四区蜜桃| 136国产福利精品导航网址应用| 亚洲精品一区在线观看| 精久久久久久| 亚洲一级片在线观看| 亚洲电影激情视频网站| 中国女人久久久| 亚洲乱码一区二区| 西西裸体人体做爰大胆久久久| 亚洲精品色婷婷福利天堂| 欧美一区二区免费视频| 女生裸体视频一区二区三区| 欧美一区二区三区四区视频| 久久久一本精品99久久精品66| 在线亚洲国产精品网站| 久久久久久伊人| 欧美在线啊v| 欧美日韩在线不卡一区| 欧美激情一区二区三区在线视频观看 | 欧美吻胸吃奶大尺度电影| 久久影院亚洲| 国产精品美女久久久久久久| 亚洲黄色在线观看| 韩国v欧美v日本v亚洲v| 亚洲性感美女99在线| 夜夜精品视频| 欧美激情视频在线免费观看 欧美视频免费一 | 性欧美激情精品| 亚洲网站啪啪| 欧美另类高清视频在线| 亚洲福利视频二区| 欧美主播一区二区三区美女 久久精品人 | 国产精品电影网站| 欧美电影在线观看完整版| 国产在线拍偷自揄拍精品| 久久黄色小说| 久久久噜噜噜久噜久久| 国产精品一级| 亚洲欧美日韩一区二区| 午夜一区在线| 国产精品一页| 午夜精品视频在线观看| 性欧美1819sex性高清| 国产欧美精品在线观看| 欧美一区二区精美| 老司机成人在线视频| 亚洲福利av| 欧美xx视频| 日韩亚洲国产精品| 亚洲欧美日韩另类| 国产欧美一区二区三区视频 | 欧美激情亚洲精品| 在线播放中文字幕一区| 久久综合色播五月| 亚洲国产一区在线| 中文亚洲欧美| 国产三区二区一区久久| 久久久精品视频成人| 亚洲第一中文字幕| 日韩视频永久免费| 国产美女扒开尿口久久久| 欧美亚洲日本一区| 欧美顶级大胆免费视频| 一本久久a久久免费精品不卡| 国产精品99免费看| 久久精品亚洲精品国产欧美kt∨| 美女日韩在线中文字幕| 日韩视频免费在线观看| 国产精品视频福利| 久久色在线播放| 亚洲国产第一页| 亚洲一区二区三区成人在线视频精品| 欧美午夜在线观看| 久久久久久久久久久成人| 亚洲第一页在线| 久久成年人视频| 亚洲电影激情视频网站| 999亚洲国产精| 亚洲丝袜av一区| 久久国产精品久久w女人spa| 在线观看一区欧美| 欧美日韩视频在线| 欧美一区午夜精品| 亚洲乱码视频| 噜噜噜躁狠狠躁狠狠精品视频| 亚洲另类在线视频| 国产欧美一区视频| 精品不卡视频| 欧美jjzz| 性xx色xx综合久久久xx| 日韩午夜在线观看视频| 免费在线亚洲| 久久狠狠一本精品综合网| av成人免费观看| 亚洲国产免费看| 韩国一区电影| 国产精品午夜在线观看| 欧美日韩激情小视频| 美玉足脚交一区二区三区图片| 亚洲婷婷国产精品电影人久久 | 亚洲毛片网站| 麻豆精品国产91久久久久久| 欧美亚洲三区| 亚洲一区在线观看视频 | 精品二区久久| 国产精品一区二区三区久久| 欧美日韩国语|