網站首頁 編程語言 正文
引入移動語義
為了能夠理解移動語義的目的,我們先從整成的一個類進行示范,示例如下:
class TestClass { public: TestClass(int s) :m_number(s) { cout << "constructor!\n"; } ~TestClass() { cout << "destructor!\n"; } // 拷貝構造 TestClass(const TestClass& that) :m_number(that.m_number) { cout << "copy constructor!\n"; } // 賦值操作符 TestClass& operator=(const TestClass& tc) { cout << "operator= is called\n"; if (this == &tc) return *this; m_number = 0; m_number = tc.m_number; return *this; } int m_number; }; TestClass tcFactory() { TestClass tc(10); return tc; } int main() { { TestClass tc = tcFactory(); } return 0; }
上面代碼的輸出結果如下:
constructor!
copy constructor!
destructor!
destructor!
可以看到進行了一次構造和一次拷貝構造,拷貝構造就發生在tc
接收tcFactory()
返回值時。這幾產生了不必要的資源消耗,如果這里可以重用或者轉移return
產生的臨時值(右值)是不是可以減少資源的消耗呢?C++正是使用轉移的方式來處理的,這個轉移就是移動構造函數,也可以說是移動語義,示例如下:
// 其他代碼不變,只增加移動構造與移動賦值處理函數 // 移動構造 TestClass(TestClass&& rr):m_number(rr.m_number) { // 如果這里是指針的變量的話則可以避免指針重復釋放的問題 rr.m_number = 0; cout << "move constructor!\n"; } // 移動賦值 TestClass& operator=(TestClass&& rr) { cout << "move operator= is called\n"; if (this == &rr) return *this; // 此步驟相當于對源指針的釋放 m_number = 0; m_number = rr.m_number; return *this; }
添加上述代碼后,輸出結果如下:
constructor!
move constructor!
destructor!
destructor!
此時第二次調用的就是移動構造,這樣可以直接使用右值,避免重新申請空間,調用兩次析構是因為,臨時對象是被延長了聲明周期,但最終也是要釋放的。
std::move
前面看到移動構造接收的是右值引用,那么在需要對左值進行移動語義的時候(進行移動語義后,此左值以后將失效),那么就必須將左值轉換為右值。此時td::move
就很好的完成了這件事情,示例如下:
int main() { vector<int> v{ 1,2,3,4 }; // 拷貝構造 vector<int> v1 = v; // 移動構造 vector<int> v2 = std::move(v); cout << "v size():" << v.size() << "\n"; cout << "v2 size():" << v2.size() << "\n"; return 0; }
上面輸出代碼為:
v size():0
v2 size():4
關于std::move
注意的幾點:
std::move
本質上只是將傳入的參數轉換為一個右值,使用static_cast
進行轉換
std::move
在進行類型推導時會保留形參的const
屬性,此時會造成一種使用失效的場景如下:
class TestClass { public: // 這么寫在 VS中也會提示 C26478 不要對常量變量使用 std::move TestClass(const string& str) :m_str(std::move(str)) { } string m_str; }; int main() { string str = "sss"; TestClass tc(str); cout << tc.m_str << "\n"; // 此處應該輸出空,但實際并非如此 , 兩個輸出都是 sss cout << str << "\n"; return 0; }
原文鏈接:https://blog.csdn.net/weixin_41111116/article/details/126452636
相關推薦
- 2022-09-07 Go泛型應用工廠方法及泛型使用_Golang
- 2022-11-30 CTF?AWD入門學習手冊_安全相關
- 2022-06-23 android中的adb命令學習_Android
- 2022-04-18 Python基礎中的的if-else語句詳解_python
- 2023-03-15 Pandas操作兩個Excel實現數據對應行的合并_python
- 2022-06-16 C#使用符號表實現查找算法_C#教程
- 2022-05-09 C#多線程之線程池ThreadPool用法_C#教程
- 2022-07-15 Sql?Server存儲過程詳解_MsSql
- 最近更新
-
- 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同步修改后的遠程分支