看板 EE_DSnP 關於我們 聯絡資訊
剛剛用open office編輯結果它當了,害我要重打,要養成存檔的好習慣。 老師下課說在版上去年這時候應該有文章,不過我找了好久都找不到阿, 後來翻閱一下手邊的工具書,覺的應該是POD造成的問題(Plain Old Data)。 寫個小程式測試一下: #include <iostream> #include <vector> using namespace std; class POD { int i; }; class NonPOD { double i; ~NonPOD() { } }; template<class T> void test() { typedef T* Pointer; Pointer p = new T[10]; void *v = reinterpret_cast<void*> (p); size_t* size = reinterpret_cast<size_t*> (v - sizeof(size_t)); cout << *size << endl; } int main() { test<POD> (); test<int> (); test<std::vector<int> > (); test<NonPOD> (); } 此程式在我的電腦編譯(g++4.4.3)執行結果為: 49 49 10 10 什麼是POD呢?簡單說就是class沒有定義constructor/copy constructor/assignment operator/destructor這四種,完全靠compiler generated版本(這個版本也稱作 trivial – constructor/....),那是POD跟這個array刪除有什麼關聯阿? 這可以從這次作業HW1.2.2這題看起,在Vector中,我們要初始化_data這個pointer, 我們會寫_data = new unsigned[size]; 如果你沒有用一個迴圈去初始化每個值,當直接 讀取 時,有時後會得到垃圾值。若我們想要讓他們都能夠初始化成unsigned的預設值呢? 可以寫: _data = new unsigned[size](); 我們再看到Matrix,在constructor內要初始化_data,不過這時候問題來了: _data = new Vector[numRows]; 會呼叫Vector的哪一個constructor阿? 如果你有用_data[1].size()去讀出它的值,會發現是0,也就是 Vector::Vector(unsigned = 0);被呼叫了。 我們可以看到,在初始化一個陣列時我們只能(implicitly or explicitly)呼叫其 default constructor,我們從int的例子可以發現,不加上()時,constructor不會被呼叫, 而不會把每個元素的初始值設為零;而在Vector的例子,編譯器有看到default constructor,因此判定它不是POD,implicitly呼叫每個元素的default ctor。 (當你把在Vector::Vector的預設參數拿掉時,編譯器就會唉啦:你沒給我一個 default constructor我怎麼建構阿?而且你已經寫了constructor了, 我更不可能幫你寫一個阿!!) 這就是編譯器對待不同類型的type會有不同的處理方式!! 如果你的class沒有寫任何constructor,編譯器就會幫你寫一份,但那份 裡面什麼都不做。 (對copy ctor跟assignment operator而言則是 memner wise assignment, 所以你呼叫Vector a(b);//利用另一個Vector b來建構a 是會通過編譯的,只不過在a,b被摧毀時delete 2 _data指的記憶體。 ) 好,重點來了,對於destructor而言,編譯器幫你寫得那份,有要作什麼用嗎? 答案是:沒有,而且對於內建型別(int double)而言也是一樣, 所以在上面的測試程式中,我們看到POD, int得到的是相似結果, 而std::vector<int>與NonPOD得到的是10的結果,也就是陣列大小。 編譯器知道陣列大小要作什麼用阿?答案就是在摧毀陣列時明白呼叫其destructor囉! for(int I = 0; I < size; ++i){ _data[I].~Vector(); } 而沒有定義destructor的POD,只要把記憶體刪除,這個物件也就掰了~~ 所以int[]與POD[]都不需要存陣列大小。 ※ 引述《puerpuella (柏亨)》之銘言: 我在寫作業的時候對delete產生了一點疑惑... 我本來以為delete是刪除一個object用的,而delete[]是刪除多個用的 但是我在main()中宣告 double* d = new double[1]; 之後不管我寫delete d; 或delete []d; 執行都會成功 而且就算我是宣告double* d = new double[0]; 時也可以 可是我寫了一個class叫做C,在main()中 C* c = new C[1]; delete c; 這樣執行就不過了,一定要用delete[]才OK 是因為宣告時如果有用[ ],delete的時候就要加嗎? 可是在double的時候好像不用加[]也行? -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.112.245.114
ric2k1:new [] 的變數用 delete 只會 delete 其中的一個,其他的 10/11 22:20
ric2k1:會變成 memory leak. 照理來說不會馬上 crash,如果會crash 10/11 22:20
ric2k1:應該是其他原因 10/11 22:21
ric2k1:簡單的說: 用 new [] 就要用 delete [], 反之用 new 則要用 10/11 22:22
ric2k1:delete. 10/11 22:22
ric2k1:明天上課會再說明一下。 10/11 22:23
puerpuella:謝謝教授!!我後來又試了一下如果我C裡面沒寫destructor 10/11 22:34
puerpuella:就不會有事,可是一加上~C()就掛了.. 10/11 22:34
ric2k1:這個跟去年的 HW1.2 P3 有關... 我明天來一起講解一下! 10/11 23:04
johnjohnlin:要作 deep copy 吧?我之前也這樣 10/12 15:50
簡單講應該也是deep copy啦XDDDDDDDDd 附註一下: Exceptional C++ (我是看國際中文版,英文版應該是3e?) Item 36:有寫到 一般的compiler在destructor通常的實做方式為, 會在dtor函式碼尾端有一個不可見旗標, 如果此變數是一個auto物件(非new出來的)則此旗標為false 若是一個dynamic物件,則此旗標為true 這個旗標代表的是『當這物件被摧毀時,我該刪除它嗎?』 如果為true,則在尾端呼叫正確(就是該class)的operator delete() (忘了說,class defined operator delete隱喻為static) 若class B有virtual dtor,且也有(static) B::operator delete(void*); class D為其derived class,但只定義(static) D::operator delete(void*); 則 D* ptr = new D; delete ptr;//喚起D::operator delete(void*) 但 B* ptr2 = new D; delete ptr2;//因為有virtual dtor,喚起~D(), ~D()內則一樣喚起D::operator delete(void*); 所以compiler其實有幫我們作一些事情的(在trivial內)。 ※ 編輯: tomap41017 來自: 140.112.244.171 (10/13 01:17)
ric2k1:推一個!! 抱歉,我說的文章是 #2451 10/13 01:11
tomap41017:突然覺的我寫得落落長 囧 10/13 01:19
ric2k1:不會啊! 講得很清楚!! 感謝 10/13 01:41
aitjcize:大推! 10/14 00:49