網站首頁 編程語言 正文
C++11在運行期有所增強,通過增加核心的右值引用機制來改善臨時對象導致的效率低下的問題。C++臨時對象引入了多余的構造、析構及其內部資源的申請釋放函數調用,導致程序運行時性能受損,這一點被廣為詬病。C++標準委員會在C++11中引入了右值引用這個核心語言機制,來提升運行期性能
過std::move,可以避免不必要的拷貝操作。
std::move是為性能而生。
std::move是將對象的狀態或者所有權從一個對象轉移到另一個對象,只是轉移,沒有內存的搬遷或者內存拷貝。
變量表達式是一個左值,即使這個變量是一個右值引用類型,也是將其看成是左值的。
于是有:變量是一個左值,我們不能將一個右值引用直接綁定到一個變量上,即使這個變量是右值引用類型也不行。
但是。我們可以顯式的將一個左值轉換為對應的右值引用類型。另外,可以通過move庫函數來獲得綁定到左值上的右值引用。此函數定義在utility中。
如:
int &&rr1 = 42; //正確,字面值常量是右值 int &&rr2 = rr1; //錯誤,表達式rr1是左值 int &&rr3 = std::move(rr1); //正確
move告訴編譯器我們有一個左值,但我們希望像一個右值一樣處理它。注意:調用move意味著承諾:除了對rr1賦值和銷毀它以外,我們不再使用它。在調用move之后,我們不能對移后源對象的值做任何假設。
(我們可以銷毀一個移后源對象,也可以賦予它新值,但是不能使用一個移后源對象的值。)
我們對move不提供using聲明,我們直接調用std::move而不是move。原因是:如果在應用程序中定義一個標準庫中已有的名字,則將出現一下兩種可能中的一種:
(1)要么根據一般的重載規則確定某次調用應該執行函數的哪個版本,
(2)要么應用程序根本就不會執行函數的標準庫版本。
因此,對于move的名字沖突相比其他標準庫函數的沖突頻繁的多。于是我們在調用move函數時,是使用std::move而不是move。
原型定義中的原理實現:
?首先,函數參數T&&是一個指向模板類型參數的右值引用,通過引用折疊,此參數可以與任何類型的實參匹配(可以傳遞左值或右值,這是std::move主要使用的兩種場景)。關于引用折疊如下:
? ? ? 公式一)X& &、X&& &、X& &&都折疊成X&,用于處理左值
? string s("hello"); std::move(s) => std::move(string& &&) => 折疊后 std::move(string& ) 此時:T的類型為string& typename remove_reference<T>::type為string? 整個std::move被實例化如下 string&& move(string& t) //t為左值,移動后不能在使用t { ? ? //通過static_cast將string&強制轉換為string&& ? ? return static_cast<string&&>(t);? } ?
? ? ? 公式二)X&& &&折疊成X&&,用于處理右值
std::move(string("hello")) => std::move(string&&) //此時:T的類型為string? // ? ? remove_reference<T>::type為string? //整個std::move被實例如下 string&& move(string&& t) //t為右值 { ? ? return static_cast<string&&>(t); ?//返回一個右值引用 }
簡單來說,右值經過T&&傳遞類型保持不變還是右值,而左值經過T&&變為普通的左值引用.
②對于static_cast<>的使用注意:任何具有明確定義的類型轉換,只要不包含底層const,都可以使用static_cast。
double d = 1; void* p = &d; double *dp = static_cast<double*> p; //正確 ? const char *cp = "hello"; char *q = static_cast<char*>(cp); //錯誤:static不能去掉const性質 static_cast<string>(cp); //正確?
③對于remove_reference是通過類模板的部分特例化進行實現的,其實現代碼如下
//原始的,最通用的版本 template <typename T> struct remove_reference{ ? ? typedef T type; ?//定義T的類型別名為type }; ? //部分版本特例化,將用于左值引用和右值引用 template <class T> struct remove_reference<T&> //左值引用 { typedef T type; } ? template <class T> struct remove_reference<T&&> //右值引用 { typedef T type; } ?? ?? //舉例如下,下列定義的a、b、c三個變量都是int類型 int i; remove_refrence<decltype(42)>::type a; ? ? ? ? ? ? //使用原版本, remove_refrence<decltype(i)>::type ?b; ? ? ? ? ? ? //左值引用特例版本 remove_refrence<decltype(std::move(i))>::type ?b; ?//右值引用特例版本?
總結:
std::move實現,首先,通過右值引用傳遞模板實現,利用引用折疊原理將右值經過T&&傳遞類型保持不變還是右值,而左值經過T&&變為普通的左值引用,以保證模板可以傳遞任意實參,且保持類型不變。然后我們通過static_cast<>進行強制類型轉換返回T&&右值引用,而static_cast<T>之所以能使用類型轉換,是通過remove_refrence<T>::type模板移除T&&,T&的引用,獲取具體類型T。
原文鏈接:https://blog.csdn.net/ypshowm/article/details/89228815
相關推薦
- 2022-06-10 nginx.conf配置文件結構小結_nginx
- 2022-12-23 Kubernetes存儲系統數據持久化管理詳解_云其它
- 2022-05-21 python?判斷文件或文件夾是否存在_python
- 2022-05-10 torch.cuda.is_available()返回false最終解決方案
- 2022-03-15 /usr/local/jdk1.8.0_144/jre/lib/amd64/libawt_xawt.
- 2022-05-15 require和import的區別詳解
- 2022-07-22 UC瀏覽器兼容問題
- 2024-01-12 maven依賴沖突以及解決方法
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支