日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

【C++ Primer | 16】std::move和std::forward、完美转发

發布時間:2023/11/30 c/c++ 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【C++ Primer | 16】std::move和std::forward、完美转发 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

右值引用應該是C++11引入的一個非常重要的技術,因為它是移動語義(Move semantics)與完美轉發(Perfect forwarding)的基石:

  • 移動語義:將內存的所有權從一個對象轉移到另外一個對象,高效的移動用來替換效率低下的復制,對象的移動語義需要實現移動構造函數和移動賦值運算符。
  • 完美轉發:定義一個函數模板,該函數模板可以接收任意類型參數,然后將參數轉發給其它目標函數,且保證目標函數接受

?

一、 引入的新規則

1. 規則1(引用折疊規則):如果間接的創建一個引用的引用,則這些引用就會“折疊”。在所有情況下(除了一個例外),引用折疊成一個普通的左值引用類型。一種特殊情況下,引用會折疊成右值引用,即右值引用的右值引用, T&& &&。即

  • X& &、X& &&、X&& &都折疊成X&
  • X&& &&折疊為X&&

2. 規則2(右值引用的特殊類型推斷規則):當將一個左值傳遞給一個參數是右值引用的函數,且此右值引用指向模板類型參數(T&&)時,編譯器推斷模板參數類型為實參的左值引用,如

template<typename T> void f(T&&);int main() {int i = 42;f(i) }

上述的模板參數類型T將推斷為int&類型,而非int。

  • 若將規則1和規則2結合起來,則意味著可以傳遞一個左值int i給f,編譯器將推斷出T的類型為int&。再根據引用折疊規則 void f(int& &&)將推斷為void f(int&)。
  • 從上述兩個規則可以得出結論:如果一個函數形參是一個指向模板類型的右值引用,則該參數可以被綁定到一個左值上
  • 規則3:雖然不能隱式的將一個左值轉換為右值引用,但是可以通過static_cast顯示地將一個左值轉換為一個右值。【C++11中為static_cast新增的轉換功能】。

?

std::move()解析

class Foo { public:std::string member;Foo(const std::string& m): member(m) {} // Copy member. Foo(std::string&& m): member(std::move(m)) {} // Move member. };

上述Foo(std::string&& member)中的member是rvalue reference,但是member卻是一個左值lvalue,因此在初始化列表中需要使用std::move將其轉換成rvalue。?

標準庫中move的定義如下:

template<typename T> typename remove_reference<T>::type&& move(T&& t) {return static_cast<typename remove_reference<T>::type &&>(t); }

move函數的參數T&&是一個指向模板類型參數的右值引用【規則2】,通過引用折疊,此參數可以和任何類型的實參匹配,因此move既可以傳遞一個左值,也可以傳遞一個右值;

std::move(string("hello"))調用解析:

  • 首先,根據模板推斷規則,確地T的類型為string;
  • typename remove_reference<T>::type && 的結果為 string &&;
  • move函數的參數類型為string&&;
  • static_cast<string &&>(t),t已經是string&&,于是類型轉換什么都不做,返回string &&;

string s1("hello"); std::move(s1); 調用解析:

  • 首先,根據模板推斷規則,確定T的類型為string&;
  • typename remove_reference<T>::type && 的結果為 string&
  • move函數的參數類型為string& &&,引用折疊之后為string&;
  • static_cast<string &&>(t),t是string&,經過static_cast之后轉換為string&&, 返回string &&;

從move的定義可以看出,move自身除了做一些參數的推斷之外,返回右值引用本質上還是靠static_cast<T&&>完成的。

因此下面兩個調用是等價的,std::move就是個語法糖。

void func(int&& a) {cout << a << endl; }int a = 6; func(std::move(a));int b = 10; func(static_cast<int&&>(b));

std::move執行到右值的無條件轉換。就其本身而言,它沒有move任何東西。

?

三、std::forward()解析?

?

class Foo { public:std::string member;template<typename T>Foo(T&& member): member{std::forward<T>(member)} {} };

傳遞一個lvalue或者傳遞一個const lvaue

  • 傳遞一個lvalue,模板推導之后 T = std::string&
  • 傳遞一個const lvaue, 模板推導之后T = const std::string&
  • T& &&將折疊為T&,即std::string& && 折疊為 std::string&
  • 最終函數為: Foo(string& member): member{std::forward<string&>(member)} {}
  • std::forward<string&>(member)將返回一個左值,最終調用拷貝構造函數

傳遞一個rvalue

  • 傳遞一個rvalue,模板推導之后 T = std::string
  • 最終函數為: Foo(string&& member): member{std::forward<string>(member)} {}
  • std::forward<string>(member) 將返回一個右值,最終調用移動構造函數;

總結:

1. std::move和std::forward本質都是轉換。std::move執行到右值的無條件轉換。std::forward只有在它的參數綁定到一個右值上的時候,才轉換它的參數到一個右值。

2. std::move沒有move任何東西,std::forward沒有轉發任何東西。在運行期,它們沒有做任何事情。它們沒有產生需要執行的代碼,一byte都沒有。

測試代碼:

#include <iostream> using namespace std;template<typename T> void PrintT(T& t) {cout << "lvaue" << endl; }template<typename T> void PrintT(T&& t) {cout << "rvalue" << endl; }template<typename T> void TestForward(T&& v) {PrintT(v);PrintT(std::forward<T>(v));PrintT(std::move(v));cout << "--------" << endl; }int main() {TestForward(1);int x = 1;TestForward(x);TestForward(std::forward<int>(x)); }

輸出結果:

?

[ 1 ].?C++11改進我們的程序之move和完美轉發
[ 2 ].?C++11 std::move和std::forward

3.?C++完美轉發

總結

以上是生活随笔為你收集整理的【C++ Primer | 16】std::move和std::forward、完美转发的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。