看板 C_and_CPP 關於我們 聯絡資訊
開發平台(Platform): (Ex: VC++, GCC, Linux, ...) VC++ 2010 問題(Question): 事情是這樣的:(以下程式碼僅為片段,完整版在最後面) VectorCpx& VectorCpx::resize(unsigned place) { VectorCpx newVec(place, Complex(0.0,0.0)); delete[] pCpx; return newVec; } fstream file("outVec.txt", ios::out); int main() { VectorCpx v1; v1.resize(10); file << v1; } 有一個 class 名叫 VectorCpx,其中有一個成員函式 resize(unsigned place) VectorCpx 的功能是能夠創一個資料型態是 Complex(複數,另一個 class)的 vector 而 resize(unsigned place) 的功能則是改變已經創好的 vector,使它填入指定數目的0 (file 是自定義輸出) 這裡我的想法是直接創一個新的 VectorCpx,按照 resize(unsigned) 的要求填入0 把原本的 VectorCpx 砍掉,回傳新的回去 但實際上執行時,卻仍然是印出舊的 VectorCpx,而我自己測試確定新的有創造成功 請問我這種寫法哪裡有問題嗎?自己看是看不出個所以然來...... 感謝大家m(_ _)m 程式碼(Code):(請善用置底文網頁, 記得排版) VectorCpx.h:http://ideone.com/a8fcFl VectorCpx.cpp:http://ideone.com/u8voXB main.cpp:http://ideone.com/ZYi9CF 補充說明(Supplement): 這個是學校的功課,如果有需要的話我再把說明文件放上來0.0 -- 吾乃 不死之眾矢之的 無右之聯合之盾 武田軍最強騎兵團首席武將 不死鬼 馬場美濃守信房是也 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 220.133.35.4
LPH66:你弄錯 resize 要做什麼了: 他要你 resize 自己不是生個新的 04/13 14:28
我知道,不過我覺得直接弄一個新的丟回去比較簡單._.
MOONRAKER:你newVec看起來沒有在任何地方指定給別人啊。 04/13 16:26
LPH66:你要丟回哪裡去? 使用者期待的是物件自己有變動啊 04/13 16:57
不太懂......0.0 我還是解釋一下resize的作用好了 resize(unsigned place, Complex cpx) 這個函式會傳入一個整數place,還有一個Complex cpx。 如果傳入的整數比vector的資料個數還大,那就把vector擴張到適合的大小,並且從原本 的資料之後一直到place的位置都填入cpx,如果當初沒有傳入cpx則填0 如果傳入的整數比vector裡面資料個數還少,那vector大小不變,但原本的資料從尾開始 砍到剩下符合的數量 例如說原本VectorCpx v1是[1][2][3][4][5][ ][ ][ ],資料個數是5,容量是8 此時v1.resize(10,6),因為10比5大,因此v1必須擴張到能夠大以塞入至少10筆資料 而原本的容量8不夠大,因此要擴張為16,之後v1裡要放入10筆資料 前面都是舊資料,後面一直到第10筆則全部填入"6" 因此變成[1][2][3][4][5][6][6][6][6][6][ ][ ][ ][ ][ ][ ],資料個數是10,容量是16 如果是v1.resize(7,6),雖然7比5大,但還在容量8範圍內,因此不用擴張陣列 變成[1][2][3][4][5][6][6][ ],資料個數是7,容量是8 如果是v1.resize(3,6),3比5小,因此不會塞入新的資料,反而舊資料要從尾砍到剩下3筆 容量不變,變成[1][2][3][ ][ ][ ][ ][ ] 至於resize(unsigned place)則是一種overload而已 我的想法是這樣: 與其要大費周章的去改變原本的v1的大小,把資料搬來搬去最後再回傳回去 倒不如直接創一個新的VectorCpx來實作這個功能 如果v1需要擴張的話,就創一個VectorCpx newVecBig(place,cpx) 這個vector的容量是我要的,資料數也是我要的,不一樣的是這個vector裡沒有舊資料 因此再把舊的資料一筆筆覆蓋到newVecBig相對應的位置上 如果v1不需要擴張,則創一個與v1相同大小的空VectorCpx newVecSmall 這個vector裡面沒有存任何的資料,因此把舊的資料一筆筆貼到相對應的位置 貼到我當初要求的資料數(place值)為止 最後再把v1 delete掉,回傳newVecBig或newVecSmall,這就是我要的vector 不過現在問題就出在不知道為什麼印出來的值仍然是v1的值...... 不知道我哪裡觀念錯誤0.0
diabloevagto:你回傳新東西是那招= = 04/13 17:20
diabloevagto:你傳回新的東西之後,你有把舊的記憶體釋放,然後 04/13 18:30
diabloevagto:回傳新的東西,但是你並沒有東西去接住 04/13 18:31
diabloevagto:原本的v1還是指向原本的v1,而不是你新回傳的 04/13 18:32
diabloevagto:你的解釋沒錯,但你複製之後應該要改掉原本的v1 04/13 18:32
喔喔大概開始有點概念了...... 不過不太知道要怎麼改,請問是用像是 this -> newVec之類的方法嗎? (不過編譯器不給我過就是,囧)
o07608:需要求救阿......OAQ 04/13 22:09
linotwo:就用你原本覺得大費周章的方式做一遍吧。 04/13 22:12
o07608:也不知道大費周章的方式怎麼做......只能想到這種方法 04/13 22:19
o07608:而且沒有搞清楚之前總是覺得不甘心._. 04/13 22:19
linotwo:配置一塊新空間 搬移 釋放舊空間 將 pCpx 指向新空間 04/13 22:22
linotwo:更新 mSize, mCapacity 04/13 22:22
喔......還有這種方法,之前居然都沒想到,囧 感謝你的提醒...... 可是我還是好想知道我原來的想法觀念要怎麼實行阿 <囧>
linotwo:物件宣告完記憶體位址就是固定的。所以可以利用指標, 04/13 22:57
linotwo:隨時讓指標指向新的位址。如果有 N 個指標就要更新 N 次 04/13 22:58
linotwo:剛好你的物件裡有個 pCpx 可以讓你指,那顯然所有人都透過 04/13 22:59
linotwo:pCpx 是最方便的。 04/13 23:00
err......不好意思,我發現我不會指,囧 如果我沒理解錯你的意思的話,那應該是要把舊vector的每個空間的pCpx 指向新的vector的每個空間的pCpx指向的位址? 但是以我對這段話及對pointer觀念的理解,寫不出來囧...... for(unsigned int i = 0; i < mCapacity; i++) *pCpx[i] = &newVec.pCpx[i]; 這是我目前想出來的鬼東西......
diabloevagto:原po的想法不是本來就應該要用 linotwo 的方式實現嗎 04/13 23:16
o07608:因為我很固執,很想看到我原本的作法能成功...... 04/13 23:36
o07608:雖然知道linotwo的作法會更好...... 04/13 23:37
rephansu:resize回傳根本就沒意義啊...XD 04/13 23:47
o07608:0.0? 04/13 23:49
diabloevagto:你的程式不能跑 04/13 23:51
diabloevagto:抓那三個也一樣,說 DBL_MIN 沒定義 04/13 23:52
0.0? 如果不管我剛才加的那段程式碼的話(那段是錯的),應該是可以跑才對阿...... 只是他cmd視窗不會有東西,會另外開一個.txt檔印出結果
diabloevagto:你印出的txt也沒東西= = 04/13 23:55
rephansu:DBL_MIN在float.h 04/13 23:55
我自己建專案跑的時候,至少確定可以印出A、B兩段阿0.0 而且也沒有跳警告說DBL_MIN找不到......奇怪
diabloevagto:反正你的問題就是你resize回傳的newVec沒有去用v1接 04/13 23:58
diabloevagto:你把main的v1.resize(10);改成v1=v1.resize(10); 04/13 23:58
結果程式當掉了......
rephansu:會當掉是因為resize時已經delete pCpx 04/14 00:04
diabloevagto:你resize回傳的時候,newVec就會被回收掉了吧 04/14 00:06
我還以為我delete的是原本v1的pCpx?!
diabloevagto:我跑程式不會當掉耶... 04/14 00:07
o07608:O囗Q 04/14 00:07
diabloevagto:你改成用指標傳就可以 04/14 00:21
diabloevagto:跟那個 delete[] pCpx; 無關 04/14 00:21
diabloevagto:http://ideone.com/oCGYH3 總共改了四個地方 04/14 00:23
diabloevagto:後面加上 //<----this 04/14 00:24
error C2679: 二元運算子 '=' : 找不到使用右方運算元型別 'VectorCpx *' 的運算子 (或是沒有可接受的轉換) 所以說我連operator=的重載函式都寫錯了嗎......
diabloevagto:我是用你給的程式,改過四個地方而已 04/14 01:05
diabloevagto:還有把你 file << v1 << v2 << v3; 之後的都刪掉 04/14 01:06
o07608:怎麼會這樣...... 04/14 01:12
rephansu:總之觀念有錯... 04/14 01:19
rephansu:假設物件是房子, pCpx是屋內的家庭成員, resize時 04/14 01:21
rephansu:又蓋了一棟房子newVec,裡面的成員是複製原始v1的成員, 04/14 01:23
rephansu:最後又把v1房子內的成員清空, 因此v1不存在合法成員 04/14 01:25
rephansu:resize這個成員函式做的事情要很明確只有重新配置pCpx 04/14 01:28
rephansu:你必須要在這個function內完成這個工作, 04/14 01:29
rephansu:若要不修改原始code, 只需要在delete[] pCpx後加上 04/14 01:35
rephansu:memcpy(this, &newVec , sizeof(VectorCpx)); 04/14 01:36
rephansu:newVec.pCpx = NULL; 04/14 01:36
rephansu:這樣就可以達到你的目的... 04/14 01:41
rephansu:你一開始問到為何印出仍是舊的,答案是delete[] pCpx時, 04/14 01:43
rephansu:pCpx指向的記憶體位置資料尚未被改變, 04/14 01:43
diabloevagto:請問如果他這樣改了,但是回傳的是new的位址, 04/14 01:46
diabloevagto:但是他在離開resize的時候就會被回收掉了,這樣錯吧 04/14 01:47
rephansu:所以印出的結果會是一樣,但這卻是不合法的取值, 04/14 01:47
rephansu:一般會建議用SAFE_DELETE的方式刪除(google有詳細) 04/14 01:49
rephansu:newVec在return時的確會被delete,但我在return之前將 04/14 01:52
rephansu:newVec.pCpx指向非法位置 04/14 01:52
rephansu:這樣就可以將newVec.pCpx存留在v1.pCpx 04/14 01:53
diabloevagto:所以這也就是存取已經被刪除的變數,什麼時候會爆炸 04/14 01:56
diabloevagto:都有可能摟? 那如果照我上面那樣改成指標可以嗎? 04/14 01:56
diabloevagto:改成指標去回傳,並且存取 04/14 01:56
這裡我想搞清楚一下0.0 所以rep大修補我的程式的方法是: 因為原本我的程式碼在delete[] pCpx之後,pCpx指向的記憶體位置裡的資料仍然沒變 (Q1:那請問我delete掉的是什麼?) 因此利用這段程式碼 memcpy(this, &newVec , sizeof(VectorCpx)); newVec.pCpx = NULL; (Q2-a:我有上網查過memcpy的用法和解釋,但還是不懂為什麼可以用在這邊......) (Q2-b:為什麼要把newVec.pCpx指向NULL?) 來把newVec.pCpx指向非法位址 (Q3:為什麼指向NULL是非法位址?因為他照理來說會在return時被delete掉嗎?) 就可以把newVec.pCpx留在v1.pCpx,以避免return時newVec被delete掉 (Q4:為什麼newVec在return時會被delete掉?) 大概是以上幾個問題還沒搞懂......
LPH66:感覺有個觀念要再提一次 (雖然 rep 在上面某處提過了) 04/14 12:20
LPH66:resize 不需要回傳東西, 使用者期望的功能是物件自己有變動 04/14 12:21
LPH66:所以原 PO 你在 resize 裡寫 return 就是這個觀念錯了而已 04/14 12:21
LPH66:所以討論到底 newVec 要給誰接個人覺得有點怪怪的就是 04/14 12:23
LPH66:那後來 rep 在提的方法其實就只是 swap 的概念而已 04/14 12:24
LPH66:把自己跟 newVec 的內容物進行交換 之後 newVec 就能扔了 04/14 12:25
感謝各位不厭其煩一直替我解惑......m(_ _)m 目前程式還是先依照我原本的作法,在rep大提供了那兩行程式碼後已經完成了99.9% 剩下的0.1%是個main裡奇怪的小問題: v3.push_back(Complex(0.5566, 0.9527)).push_back(Complex(0.2, 0.3)); 這樣會出問題,似乎是讀不到後面的push_back v3.push_back(Complex(0.5566, 0.9527)); v3.push_back(Complex(0.2, 0.3)); 這樣就對了 而push_back的程式碼內容都沒變,不知道為什麼...... 除此之外,這個程式基本上已經完成了 等段考完後,我會再用原本應該要用的正確觀念─使用者期望物件自己的變動 來把這個程式重寫一遍,不過這次也是學到了很多東西 現在希望先能把rep大講的那些東西好好搞懂...... (問題在上面0.0) 再次感謝大家的不辭勞苦 m(_ _)m
o07608:等那些問題搞懂,寫好註解之後,我再把目前最終版程式碼 04/14 15:02
o07608:貼上來0.0 04/14 15:02
o07608:請問有人能幫我解惑嗎......0.0? 04/14 22:54
zetab:delete只是告訴OS這個空間不再使用 並不會清掉空間裡的資料 04/15 00:18
zetab:memcpy幫你把newVec的資料複製到你目前的這個物件 04/15 00:37
zetab:把指標指向NULL只是讓你不小心存取到這個指標時看得出錯誤 04/15 00:39
zetab:提取NULL指標的內容會產生runtime error 讓你看得出錯誤 04/15 00:40
zetab:newVec是local variable所以離開function後就會消失 04/15 00:41
zetab:return一個local variable的reference不合法的 04/15 00:43
zetab:感覺你似乎不清楚變數的生命週期 先把這部分搞懂吧 04/15 00:44
總之我這次捅了個麻煩的大洞......0.0,等考完我再把這部份好好的磨助教磨到懂 以下是目前的最終版本 VectorCpx.h:http://ideone.com/qT1F8O VectorCpx.cpp:http://ideone.com/J00SSs main.cpp:http://ideone.com/awxpCS 有大家的幫忙,才能完成這份功課 最後希望我明後天的期中考能順利過關>"< ※ 編輯: o07608 來自: 220.133.35.4 (04/15 18:39)
o07608:話說codepad最近怎麼都連不上去...... 04/15 18:41