溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C++中什么時候使用std::move?

發布時間:2021-11-26 13:53:09 來源:億速云 閱讀:469 作者:iii 欄目:大數據

這篇文章主要講解了“C++中什么時候使用std::move”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“C++中什么時候使用std::move”吧!

ES.56:只在需要將一個對象顯式移動到另外的作用域時使用std::move

Reason(原因)

我們使用move而不是copy是為了避免不必要的重復并提高性能。

移動操作一般會留下一個空對象(C.64),它可能引起誤解甚至危險。因此我們努力避免移動左值(它們可能在后續代碼中被使用)。

Notes(注意)

如果源數據是右值,移動操作會隱式進行(例如return處理或函數的返回值),在這種情況下進行顯式移動操作,會導致代碼被漫無目標地的復雜化。相反,編寫帶返回值的簡短函數,這樣無論是函數的返回值還是調用側的接受動作都可以很自然地被優化。

通常情況下,遵循本文檔中的準則(包括不要不必要地擴大變量作用域,編寫帶返回值的簡短函數,返回局部變量等)可以幫助消除顯式執行std::move的大部分需求。

在顯式移動一個對象到另外的作用域時,顯式移動是有必要的。特別是:

1.將對象傳遞給一個“下沉”函數時(接管變量所有權的函數,譯者注)

2.實現對象自身移動操作(移動構造函數,移動賦值運算符)和交換操作時

Example, bad(反面示例)

void sink(X&& x);   // sink takes ownership of x

void user()
{
   X x;
   // error: cannot bind an lvalue to a rvalue reference
   sink(x);
   // OK: sink takes the contents of x, x must now be assumed to be empty
   sink(std::move(x));

   // ...

   // probably a mistake
   use(x);
}

通常情況下,std::move()作為為&&參數提供實參。而且在移動之后,應該認為對象已經被移走(參見C.64)并且在賦予新值之前不要獲取對象的狀態。

void f() {
   string s1 = "supercalifragilisticexpialidocious";

   string s2 = s1;             // ok, takes a copy
   assert(s1 == "supercalifragilisticexpialidocious");  // ok

   // bad, if you want to keep using s1's value
   string s3 = move(s1);

   // bad, assert will likely fail, s1 likely changed
   assert(s1 == "supercalifragilisticexpialidocious");
}
Example(示例)
void sink(unique_ptr<widget> p);  // pass ownership of p to sink()

void f() {
   auto w = make_unique<widget>();
   // ...
   sink(std::move(w));               // ok, give to sink()
   // ...
   sink(w);    // Error: unique_ptr is carefully designed so that you cannot copy it
}
Notes(注意)

std::move()實際上是目標為&&的類型轉換;它自己不會移動任何東西,而是將命名對象標記為一個移出操作的候選者。語言已經知道對象可以被移出的一般情況,特別是函數的返回值,因此不要因為多余的std::move導致代碼復雜化。

永遠不要只是因為聽說它更高效就使用std::move。通常不要相信那些脫離具體數據的所謂“高效”。通常不要沒有理由地讓代碼復雜化。永遠不要對常量對象調用std::move(),這會不知不覺地產生一個拷貝。

Example, bad(反面示例)

vector<int> make_vector() {
   vector<int> result;
   // ... load result with data
   return std::move(result);       // bad; just write "return result;"
}

永遠不要返回局部變量的移動結果;因為語言已經知道這個變量可以作為移動操作的候選,在這種代碼中增加move代碼不但沒有任何幫助,而且對于某些編譯器,由于產生了額外的指向局部變量的引用,增加move代碼會影響RVO(返回值優化)的正常執行。

Example, bad(反面示例)

vector<int> v = std::move(make_vector());   // bad; the std::move is entirely redundant

如果函數f以傳值方式返回結果,永遠不要對這個返回值調用move操作,例如X=move(f());語言已經知道返回值是臨時變量并且可以進行移出操作。

Example(示例)

void mover(X&& x) {
   call_something(std::move(x));         // ok
   call_something(std::forward<X>(x));   // bad, don't std::forward an rvalue reference
   call_something(x);                    // suspicious, why not std::move?
}

template<class T>
void forwarder(T&& t) {
   call_something(std::move(t));         // bad, don't std::move a forwarding reference
   call_something(std::forward<T>(t));   // ok
   call_something(t);                    // suspicious, why not std::forward?
}
Enforcement(實施建議)
  • 標記針對右值或者已經被語言看作是右值的對象調用std::move的情況。包括std::move(local_variable);,std::move(f()),這里函數f是一個以傳值方式返回結果的函數。

  • 標記沒有用于處理左值的const S&型重載函數,只有一個處理右值(參數類型:S&&)的函數的情況。

  • 標記向參數傳遞std::move執行結果的情況,除非參數類型是右值引用類型X&&,或者參數類型為只移動不拷貝類型并且以傳值方式傳遞。

  • 標記對轉交引用類型調用std::move的情況(T&&,這里T是模板參數)。

  • 標記std::move運用于指向非常變量的右值引用以外的情況。(前面規則的更普遍形式,以包含非轉交參數的情況)

  • 標記std::forward用于右值引用的情況(X&&,這里X是具體類型),轉而使用std::move。

  • 標記std::forward用于轉交引用之外的情況。(前面規則的更普遍形式,它可以覆蓋非移動參數的情況。)

  • 標記對象可能被執行移出操作而且下一個是常量操作(讀取對象值,譯者注)的情況;哪里應該首先有一個非常量操作(以便修改對象值,譯者注),最好是重新設置對象值的賦值操作。

    感謝各位的閱讀,以上就是“C++中什么時候使用std::move”的內容了,經過本文的學習后,相信大家對C++中什么時候使用std::move這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    c++
    AI

    亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女