【C/C++】論新生如何自我介紹?(裝逼)|遊戲引擎一(基礎篇)thirteen告訴你!
c++ 提供了變數 copy (複製)方式,當然是有一定的原因。 copy 在某些場景是很有好的解決方案,但相反一面,多數情況我們也應儘量避免 copy,因為 copy 會浪費時間,降低效率。畢竟我們寫 c++的目的就是追求效率。
現在我們看一下 c++ 是如何實現 copy 的,如果瞭解了 copy 的實現方式,我們就能更好地使用 copy 和合理地避免濫用 copy。
開始程式碼演示
對於基本資料型別:定義一個基本型別變數 a ,然後將變數 b 等於 a,這時變數 b 是 a 的 copy。但 a 和 b 指向不同的記憶體地址,所以當更改了變數 b 的值,不會影響到變數 a。
對於複合資料型別:class/struct 和基本型別是一樣的,我們將 a 的 copy 一份複製給 b, a 和 b 還是指向不同記憶體的地址。
我們可以在堆記憶體中建立一個 Vector2 例項,將建立好的 Vector2 物件用記憶體指標地址 a。 這裡b copy 的 a
指向的記憶體的地址,也就是 a b 都是指向一個記憶體地址。所以當修改了 b->x 屬性值,也就是等於修改了 a->x
的屬性值。可以想象我們這裡,是將以一個引用賦值給另一個引用,他們都引用相同的記憶體地址。
接下來,進一步討論一下 copy,現在自己來實現一個 String 類。首先我們明確一下 String 應該是由一系列字母組成的,所以在
private 定義指標 m_Buffer 用於儲存 char 型別資料,再定義 m_Size 為 String 包含字母的數量。
String 建構函式接受指標 string (為 chart 型別陣列)建構函式中要做兩件事,第一件就是計算字串的長度,然後賦值給
m_Size ,然後就是將 string 指標指向記憶體地址中的資料賦值給 m_Buffer。我們可以for迴圈 string 然後將
string 中內容賦值給 m_Buffer。
這裡 memcpy 接受三個引數,第一個引數為複製的目標,第二個引數複製的源,第三引數為複製的長度。
建立好 String 的建構函式,我們還需讓 String 可以輸出 m_Buffer 中的內容。
這裡使用 friend ,以便函式可以呼叫 string 類中的 private 屬性 m_Buffer。
將 GetBuffer() 方法替換為 m_Buffer 以輸出 m_Buffer 中的內容。
由於沒有標識字串結束(也就是字母組成的陣列)這裡才會有除了 jangwoo 後面的其他符號。連續記憶體地址中儲存字元組成的字串,最後應該有用 0 佔位的記憶體地址。表示字串結束。
要處理掉這個問題很簡單,只需要在為 m_Buffer 分配地址時加上一個位元組,即可。表示字串結束。
由於 m_Buffer 是通過 new 關鍵字建立的,佔用堆記憶體。我們需要在 String 的解構函式中將 m_Buffer 佔用的記憶體釋放掉。
建立String 型別的變數 string 賦值為 “jangwoo” ,然後 string 賦值給變數 second。試著在終端輸出 string 和 second 。執行程式,發現報錯了
解釋一下吧,同一個型別變數 second 和 string 經過複製後,這兩個變數中儲存的 m_buffer 變數指向同一個記憶體地址。
我們為 String 型別新增一個方法,這個方法用於根據 index 獲取對應位置上字元。
這裡複製是淺複製,所以當執行到解構函式,就會重複釋放 m_Buffer
兩次,因此才報錯。我們需要深複製來避免這個問題。要實現深度複製,我們需要建立一個建構函式 String 在這個建構函式我們新建 m_Buffer
,這樣就不會指向一個同一個 m_Buffer 的記憶體地址。