移動構造函數

 

 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 }

運行結果:
ios

首先說說爲何會這樣輸出:函數

一、第一個 「默認構造函數」 是由於vector<Test> vec(1) , 因此事先使用默認構造函數構造了一個Test對象this

二、第二個 「默認構造函數」 是由於Test t ,使用默認構造函數構造了一個對象spa

三、第三個 「移動構造函數」 大多數人會覺得是 vec.push_back(std::move(t)) ,push_back 致使對象的移動而輸出的。具體的緣由實際上是因爲從新分配內存而致使的,咱們的 vector 對象 vec 初始的容量只有 1 ,且裏面已經有一個對象了,就是vector<Test> vec(1)的時候建立的,因此再向vec裏面添加Test對象時,就會致使vec從新分配內存。因爲vec中的對象定義了移動構造函數且是可用的(由於咱們將其聲明爲了noexcept),因此就會調用移動構造函數將vec中原始的那個對象移動到新的內存中,從而輸出 「移動構造函數」。.net

四、第四個 「移動構造函數」 纔是由於Test 對象 t 被移動到vector 對象 vec 新的空間而輸出的3d

五、第五個 「析構函數」 是由於從新分配內存後,原來的內存將被銷燬,因此輸出一個「析構函數」code

六、後面三個 「析構函數」 是由於執行了return 0, 內存被釋放,vec 和 t 都被析構,因此輸出三個 「析構函數」對象

將 Test.h 和 Test.cpp 文件中的noexcept 都刪去,輸出的結果變成了:blog

更改以後的輸出只有第四行的輸出變了,其他行輸出緣由與上面是同樣的內存

第四行的輸出由 「移動構造函數」 變成了 「拷貝構造函數」 ,緣由是:

因爲咱們的移動構造函數沒有聲明爲noexcept,因此咱們的移動構造函數就會被認爲是可能拋出異常,因此在從新分配內存的過程當中,vec 對象就會使用拷貝構造函數來「移動」對象(這裏說的移動實際上是拷貝,並非移動),因此就輸出了「拷貝構造函數」。

參考資料

1. C++筆記之移動構造函數什麼時候會被調用,什麼時候不會被調用

相關文章
相關標籤/搜索