移动构造函数
?
1 #include<iostream> 2 #include<vector> 3 #include<string> 4 using namespace std; 5 6 class Test 7 { 8 public: 9 Test(const string& s = "hello world") :str(new string(s)) { cout << "默認構造函數" << endl; }; 10 Test(const Test& t); 11 Test& operator=(const Test& t); 12 Test(Test&& t) noexcept; 13 Test& operator=(Test&& t) noexcept; 14 ~Test(); 15 public: 16 string * str; 17 }; 18 19 Test::Test(const Test& t) 20 { 21 str = new string(*(t.str)); 22 cout << "拷貝構造函數" << endl; 23 } 24 Test& Test::operator=(const Test& t) 25 { 26 cout << "拷貝賦值運算符" << endl; 27 return *this; 28 } 29 Test::Test(Test&& t)noexcept 30 { 31 str = t.str; 32 t.str = nullptr; 33 cout << "移動構造函數" << endl; 34 } 35 Test& Test::operator=(Test&& t)noexcept 36 { 37 cout << "移動賦值運算符" << endl; 38 return *this; 39 } 40 Test::~Test() 41 { 42 cout << "析構函數" << endl; 43 } 44 45 int main() 46 { 47 vector<Test> vec(1); 48 Test t("what"); 49 vec.push_back(std::move(t)); 50 return 0; 51 }
運行結果:
首先說說為什么會這樣輸出:
1、第一個 “默認構造函數” 是因為vector<Test> vec(1) , 所以事先使用默認構造函數構造了一個Test對象
2、第二個 “默認構造函數” 是因為Test t ,使用默認構造函數構造了一個對象
3、第三個 “移動構造函數” 大多數人會以為是 vec.push_back(std::move(t)) ,push_back 導致對象的移動而輸出的。具體的原因其實是由于重新分配內存而導致的,我們的 vector 對象 vec 初始的容量只有 1 ,且里面已經有一個對象了,就是vector<Test> vec(1)的時候創建的,所以再向vec里面添加Test對象時,就會導致vec重新分配內存。由于vec中的對象定義了移動構造函數且是可用的(因為我們將其聲明為了noexcept),所以就會調用移動構造函數將vec中原始的那個對象移動到新的內存中,從而輸出 “移動構造函數”。
4、第四個 “移動構造函數” 才是因為Test 對象 t 被移動到vector 對象 vec 新的空間而輸出的
5、第五個 “析構函數” 是因為重新分配內存后,原來的內存將被銷毀,所以輸出一個“析構函數”
6、后面三個 “析構函數” 是因為執行了return 0, 內存被釋放,vec 和 t 都被析構,所以輸出三個 “析構函數”
將 Test.h 和 Test.cpp 文件中的noexcept 都刪去,輸出的結果變成了:
更改之后的輸出只有第四行的輸出變了,其余行輸出原因與上面是一樣的
第四行的輸出由 “移動構造函數” 變成了 “拷貝構造函數” ,原因是:
由于我們的移動構造函數沒有聲明為noexcept,所以我們的移動構造函數就會被認為是可能拋出異常,所以在重新分配內存的過程中,vec 對象就會使用拷貝構造函數來“移動”對象(這里說的移動其實是拷貝,并不是移動),所以就輸出了“拷貝構造函數”。
參考資料
1. C++筆記之移動構造函數何時會被調用,何時不會被調用
轉載于:https://www.cnblogs.com/sunbines/p/9068987.html
總結
- 上一篇: 求粗开头的成语接龙!
- 下一篇: 缅甸花梨木目前的价格一吨多少钱