推 jerryh001: 是要定義copy constructor沒錯 看看有沒有哪裡寫錯 10/08 21:07
→ jerryh001: 發現個奇怪的地方 destructor不應該手動呼叫 10/08 21:08
→ s5031588: 請問j大 copy constructor該怎麼寫呢?因為我造我的邏 10/08 22:07
→ s5031588: 輯寫還是沒辦法欸..附上我copy constructor的程式碼: 10/08 22:08
→ s5031588: 我用一步步執行發現,雖然copy function不會讓兩個 10/08 22:21
→ s5031588: POINTER 直接相等,但是splitStack一結束,居然會 10/08 22:22
→ s5031588: 兩個指標都destruct...= =,有人可以解釋原理嗎QQ 10/08 22:22
→ jerryh001: operator=也要留吧 10/08 22:40
→ jerryh001: copy ctor 的參數也許也要<T>嗎? 有點忘了 10/08 22:42
→ stucode: 怎麼寫完 copy ctor 後 operator = 就不見了XD? 10/08 23:20
→ stucode: 1. copy constructor 裡面不用 delete,因為是初始化, 10/08 23:20
→ stucode: 還沒有前值,直接 new 然後 copy 就好。 10/08 23:20
→ stucode: 2. copy assignment 需要檢查並釋放(或重新利用)現有 10/08 23:20
→ stucode: 資源,同時要避免 self-assignment 造成錯誤的 10/08 23:21
→ stucode: delete。 10/08 23:21
→ stucode: 3. copy assignment 請傳回 reference,不要傳值。 10/08 23:21
→ stucode: 4. splitStack() return first 就好,不用再包一層。 10/08 23:21
→ stucode: 其實你的指標幾乎都是在 3. 或 4. 多餘的臨時物件中被 10/08 23:21
→ stucode: delete 掉的。不過如果有做好 deep copy,頂多就是多跑 10/08 23:22
→ stucode: 幾次 copy 效能較差而已,也不至於會使用到被 delete 10/08 23:22
→ stucode: 掉的指標,造成嚴重錯誤。 10/08 23:22
喔喔喔瞭解了,真的是犯傻才會把operator=又刪掉XDD,現在程式可以work了,
非常感謝j大跟s大的解說!
不過想另外請教s大,關於第三點,為什麼會說傳回reference呢?是因爲傳回值
有什麼缺點嗎?謝謝。
※ 編輯: s5031588 (114.47.182.50), 10/09/2017 00:44:19
推 lc85301: 傳回reference 是要允許使用 move 來減少一次 copy 吧 10/09 01:04
→ stucode: 傳回值的話,比較容易產生不必要的臨時物件。除此之外, 10/09 05:57
→ stucode: 還可能導致非使用者預期的行為。其實 C++ 並沒有硬性規 10/09 05:57
→ stucode: 定 copy assignment 要傳回 reference。這比較像是一種 10/09 05:57
→ stucode: 慣例,讓自定義類別的行為盡可能相似於 C++ 原生型別 10/09 05:58
→ stucode: (如 int)的行為。減少類別使用時產生意料之外的效果。 10/09 05:58
→ stucode: 另外一個理由是,CopyAssignment requirements 要求回傳 10/09 05:58
→ stucode: 型態必須是 T&,沒有滿足這個條件可能無法正常使用某些 10/09 05:58
→ stucode: 標準容器的方法。事實上,如果沒有為類別宣告這個函數, 10/09 05:58
→ stucode: 編譯器自動幫你生成的版本也是傳回 reference。當然,如 10/09 05:58
→ stucode: 果你有更好的理由傳回新物件或者是其他型別,那就不用客 10/09 05:58
→ stucode: 氣的傳吧!只要確保使用者了解並正確使用你的類別即可。 10/09 05:59
謝謝s大與l大的回覆,原來回傳值會產生一個臨時物件,一直以為回傳的值會直接
回到main,由main裡面的物件去接收...看來我原本誤會很深
再次感謝三位的回覆。
※ 編輯: s5031588 (49.215.209.133), 10/09/2017 09:16:04
推 james732: 順便學一下什麼是rvalue reference與move吧XD 10/09 10:02
回james:好的我會研究看看,謝謝建議。
照著大家說得下去改了程式碼:http://codepad.org/RYcz2e7B
main:http://codepad.org/cM17bFfK
為什麼我原本用b=a.splitStack(1)的時候,當等式結束的時候splitStack()裡面的first
會被destructor給刪除,然而改成上面main裡面的方式用Stack b(a.splitStack(1))時,
卻沒有呼叫destructor來解構first的跡象...?
另外,為什麼用copy assignment的時候,似乎是等到等號結束時,程式才會呼叫
destructor來解構first,而不是splitStack一結束就呼叫呢?
我好亂啊..QQ
※ 編輯: s5031588 (49.215.209.133), 10/09/2017 10:52:07
→ Caesar08: 如果你想要預先allocate一些memory來用,你需要知道 10/09 13:50
→ Caesar08: placement new才行。今天destructor沒問題是因為T是int 10/09 13:50
→ Caesar08: 建議先看gcc或msvc的vector怎麼實作vector,再實作stack 10/09 13:51
→ stucode: 實測了一下,解構都正常喔。如果你有開最佳化(或者是 10/09 20:09
→ stucode: IDE 的 Release mode),那 first 可能被 RVO 掉,實際 10/09 20:09
→ stucode: 解構會在 b 生命週期結束時(離開 main() 時)發生。 10/09 20:09
→ stucode: 另外,複製建構函數裡的 new 括號錯了。 10/09 20:09
謝謝c大的回答,我會再參考看看。
回s大:我不知道我有沒有開最佳化欸,我不管在xcode裡面跑(似乎是debug mode
我也不知道怎麼看,整個IDE我只會有按過run跟新增專案而已..慘)還是用終端機跑
g++-5 main.cpp的指令出來的結果就是destructor只被呼叫了兩次(最後離開main的時
候),後來一步步看,似乎跑的時候系統一開始就直接把first.stack與b.stack指向
同一個地方了,所以最後destructor只有呼叫兩次,一次是delete a.stack
另一次是delete b.stack(first.stack),似乎這就是s大你說的first被RVO..
再次感謝s大,還讓你幫我跑一次~
※ 編輯: s5031588 (36.236.99.33), 10/10/2017 12:16:25