剖析——移动构造函数
移動構造函數應用的場景????
答:有時候我們會遇到這樣一種情況,我們用對象a初始化對象b,后對象a我們就不在使用了,但是對象a的空間還在呀(在析構之前),既然拷貝構造函數,實際上就是把a對象的內容復制一份到b中,那么為什么我們不能直接使用a的空間呢?這樣就避免了新的空間的分配,大大降低了構造的成本。這就是移動構造函數設計的初衷。
?
例子示下:
#include<string> #include<vector> using namespace std;class String; ostream& operator<<(ostream& out, String& s); class String { public:friend ostream& operator<<(ostream& out, String& s); public:String(const char* data = ""){if (data == NULL){m_data = new char[1];m_data[0] = '\0';}else{m_data = new char[strlen(data) + 1];strcpy(m_data, data);}cout << "constructor execute..." << endl;}String(String &&s)noexcept{cout << "move constructor execute..." << endl;m_data = NULL;this->m_data = s.m_data;s.m_data = NULL;}~String(){cout << this<<"free execute..." << endl;if(m_data != NULL)delete[] m_data;} private:char* m_data; };ostream& operator<<(ostream& out, String& s) {out << s.m_data;return out; } int main() {String s = "hello";vector<String> vs(1);vs.push_back(std::move(s));return 0; }執行結果:
解析運行結果:
1、第一個 “默認構造函數” 是因為vector<String> vs(1) , 所以事先使用默認構造函數構造了一個Test對象
2、第二個 “默認構造函數” 是因為Test t ,使用默認構造函數構造了一個對象
3、第三個 “移動構造函數” 大多數人會以為是 vec.push_back(std::move(s)) ,push_back 導致對象的移動而輸出的。具體的原因其實是由于重新分配內存而導致的,我們的 vector 對象 vs 初始的容量只有 1 ,且里面已經有一個對象了,就是vector<Test> vs(1)的時候創建的,所以再向vs里面添加String對象時,就會導致vs重新分配內存。由于vs中的對象定義了移動構造函數且是可用的(因為我們將其聲明為了noexcept),所以就會調用移動構造函數將vs中原始的那個對象移動到新的內存中,從而輸出 “移動構造函數”。
4、第四個 “移動構造函數” 才是因為String對象 t 被移動到vector 對象 vs 新的空間而輸出的
5、第五個 “析構函數” 是因為重新分配內存后,原來的內存將被銷毀,所以輸出一個“析構函數”
6、后面三個 “析構函數” 是因為執行了return 0, 內存被釋放,vs 和 s 都被析構,所以輸出三個 “析構函數
?
注意:
第四行的輸出由 “移動構造函數” 變成了 “拷貝構造函數” ,原因是:
由于我們的移動構造函數沒有聲明為noexcept,所以我們的移動構造函數就會被認為是可能拋出異常,所以在重新分配內存的過程中,vs對象就會使用拷貝構造函數來“移動”對象(這里說的移動其實是拷貝,并不是移動),所以就輸出了“拷貝構造函數”。
?
轉載于:https://www.cnblogs.com/single-dont/p/11328524.html
總結
以上是生活随笔為你收集整理的剖析——移动构造函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 对象重写tostring
- 下一篇: 基于UDP协议的套接字+socketse