C++移動語義介紹與使用講解
引入移動語義
為了能夠理解移動語義的目的,我們先從整成的一個類進行示范,示例如下:
class TestClass { public: TestClass(int s) :m_number(s) { cout << "constructor!\n"; } ~TestClass() { cout << "destructor!\n"; } // 拷貝構(gòu)造 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; }
上面代碼的輸出結(jié)果如下:
constructor!
copy constructor!
destructor!
destructor!
可以看到進行了一次構(gòu)造和一次拷貝構(gòu)造,拷貝構(gòu)造就發(fā)生在tc
接收tcFactory()
返回值時。這幾產(chǎn)生了不必要的資源消耗,如果這里可以重用或者轉(zhuǎn)移return
產(chǎn)生的臨時值(右值)是不是可以減少資源的消耗呢?C++正是使用轉(zhuǎn)移的方式來處理的,這個轉(zhuǎn)移就是移動構(gòu)造函數(shù),也可以說是移動語義,示例如下:
// 其他代碼不變,只增加移動構(gòu)造與移動賦值處理函數(shù) // 移動構(gòu)造 TestClass(TestClass&& rr):m_number(rr.m_number) { // 如果這里是指針的變量的話則可以避免指針重復(fù)釋放的問題 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; }
添加上述代碼后,輸出結(jié)果如下:
constructor!
move constructor!
destructor!
destructor!
此時第二次調(diào)用的就是移動構(gòu)造,這樣可以直接使用右值,避免重新申請空間,調(diào)用兩次析構(gòu)是因為,臨時對象是被延長了聲明周期,但最終也是要釋放的。
std::move
前面看到移動構(gòu)造接收的是右值引用,那么在需要對左值進行移動語義的時候(進行移動語義后,此左值以后將失效),那么就必須將左值轉(zhuǎn)換為右值。此時td::move
就很好的完成了這件事情,示例如下:
int main() { vector<int> v{ 1,2,3,4 }; // 拷貝構(gòu)造 vector<int> v1 = v; // 移動構(gòu)造 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
關(guān)于std::move
注意的幾點:
std::move
本質(zhì)上只是將傳入的參數(shù)轉(zhuǎn)換為一個右值,使用static_cast
進行轉(zhuǎn)換
std::move
在進行類型推導(dǎo)時會保留形參的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"; // 此處應(yīng)該輸出空,但實際并非如此 , 兩個輸出都是 sss cout << str << "\n"; return 0; }
到此這篇關(guān)于C++移動語義介紹與使用講解的文章就介紹到這了,更多相關(guān)C++移動語義內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C/C++中不同數(shù)據(jù)類型之間的轉(zhuǎn)換詳解
這篇文章主要介紹了C/C++中不同數(shù)據(jù)類型之間的轉(zhuǎn)換詳解,數(shù)據(jù)類型轉(zhuǎn)換是計算機編程中常見的操作,用于將一個數(shù)據(jù)類型轉(zhuǎn)換為另一個數(shù)據(jù)類型,本文將對不同數(shù)據(jù)類型之間的轉(zhuǎn)換作出說明,需要的朋友可以參考下2023-10-10C++類成員構(gòu)造函數(shù)和析構(gòu)函數(shù)順序示例詳細講解
這篇文章主要介紹了C++類成員構(gòu)造和析構(gòu)順序示例,看了這個例子大家就可以明白c++構(gòu)造析構(gòu)的奧秘2013-11-11C語言數(shù)據(jù)結(jié)構(gòu)哈希表詳解
哈希表是一種根據(jù)關(guān)鍵碼去尋找值的數(shù)據(jù)映射結(jié)構(gòu),該結(jié)構(gòu)通過把關(guān)鍵碼映射的位置去尋找存放值的地方,說起來可能感覺有點復(fù)雜,我想我舉個例子你就會明白了,最典型的的例子就是字典2022-02-02