Re: [問題] placement new & copy ctor

看板C_and_CPP作者 (黑駿)時間12年前 (2012/06/01 02:13), 編輯推噓1(1026)
留言27則, 3人參與, 最新討論串2/2 (看更多)
※ 引述《xatier (xatier)》之銘言: : 開發平台(Platform): (Ex: VC++, GCC, Linux, ...) : Ubuntu Linux / g++ 4.6 : 問題(Question): : http://ideone.com/f1Ctt : 我先用 operator new [] 要了一塊空間給 p 說好的 operator new[] 結果你用了 operator new .... : 之後想把 p 裏面每個元素都用 kerker 這個物件 initialize : 我的想法是透過 copy constructor 把 kerker 複製一份後塞給 p 裏面的空間 : 這樣似乎會造成 runtime error ? : 然後又做了實驗,把 : *p = T(kerker); 這個其實做了兩件事: 1. T temp(kerker); 呼叫 copy ctor 初始化一個暫時物件 2. *p = temp; 使用 copy assignment 把值複製進 *p 但事實上 temp 會被 optimize 掉,變成 kerker 直接 copy assigment 進 *p 所以執行時不會看到有關 temp 的東西 重點是,使用了 copy assigment 在這裡因為沒寫 operator= 所以使用預設 但 *p 根本還沒初始化過,string a 同樣也是沒初始化的狀態 呼叫 string::operator= 時死掉了 : 換成 : p = new T(kerker); : 這樣就能成功 這個也是做兩件事,但是不太一樣: 1. T temp(kerker); 呼叫 copy ctor 初始化一個暫時物件 2. p = &temp; 把 p 指向這個暫時物件 這並不會動到沒初始化的東西,所以 OK : 同樣都是去 call T 的 copy constructor : 兩者是差在那邊呢@@? 然後…最後要記得 for(int i=0; i<3; i++) p[i].~T(); operator delete[] (p);

05/31 23:34,
直接寫 T *p = new T[3]; 就可以啦
05/31 23:34
在這個範例中確實可以 但如果今天 T 沒有 T() 可以用,這個方法就失敗了

05/31 23:38,
根據網友 adxis 的水球,好像可以用 new (p+i) T(kerker);
05/31 23:38
這是正解 不過不要忘記把 p++; 拿掉… 話說寫 p++; 的話之後不就不能用了嗎0.0 (除非再減回來)

05/31 23:38,
研究中...
05/31 23:38

05/31 23:39,
http://tinyurl.com/3yaaj4y 你那樣寫 就是他範例的case 3
05/31 23:39

05/31 23:39,
沒跑constructor 所以你的string a沒被建構 裡面出了啥差錯
05/31 23:39

05/31 23:40,
不得而知
05/31 23:40

05/31 23:41,
但是這樣就失去 placement new的意義了~
05/31 23:41

05/31 23:42,
Hmmm... 原來如此,我再試試看 >"<
05/31 23:42

05/31 23:44,
啊我想錯了~用a大的方式就沒有錯 但是會發生exception原因
05/31 23:44

05/31 23:44,
還是滿好奇的....
05/31 23:44
我也不知道為什麼 placement new 還會發生 exception... orz

05/31 23:50,
你*p = 是呼叫T的operator = 但你沒寫這optr 所以她在做copy
05/31 23:50

05/31 23:51,
的時候 string a = T(kerker).a 壞掉了
05/31 23:51
-- 光明 的背後 是 黑暗 黑暗 的背後 還是 黑暗 由此可知 黑暗 > 光明 Q.E.D. -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.113.230.123 ※ 編輯: darkgerm 來自: 140.113.230.123 (06/01 02:17)

06/01 02:15, , 1F
推薦這個萌神圳!清晰易懂!
06/01 02:15, 1F
※ 編輯: darkgerm 來自: 140.113.230.123 (06/01 02:19)

06/01 02:42, , 2F
最後最好是那樣寫...
06/01 02:42, 2F

06/01 02:43, , 3F
沒事看錯
06/01 02:43, 3F
不好意思,是我寫不清楚 如果這樣要到空間: T *p = (T *)operator new[] (sizeof(T) * 3); for(int i=0; i<3; i++) new (p+i) T(kerker); 那就要這樣 delete for(int i=0; i<3; i++) p[i].~T(); operator delete[] (p);

06/01 02:43, , 4F
應該是直接 delete p[i] ?
06/01 02:43, 4F

06/01 02:45, , 5F
p = new T(kerker); 不是暫時物件
06/01 02:45, 5F
恩…應該說是「配一個新的空間給 p」?

06/01 02:45, , 6F
[問] 如果 delete p[i] 後再 operator delete [] (p) 會造
06/01 02:45, 6F

06/01 02:46, , 7F
成 double free 的情況嗎@@ 不是說有 new 就要有對應的
06/01 02:46, 7F

06/01 02:46, , 8F
delete,有 operator new [] 就要有 operator delete [] ?
06/01 02:46, 8F

06/01 02:47, , 9F
darkgerm 學長直接呼叫 ~T() 是正確的作法嗎?
06/01 02:47, 9F

06/01 02:49, , 10F
你的作法最好想成 malloc 一塊足以放置數個物件的記憶
06/01 02:49, 10F

06/01 02:50, , 11F
體, 然後在每個適當位置建構起物件, 最後當然是要free
06/01 02:50, 11F

06/01 02:51, , 12F
那一大塊記憶體, 但並不是在每個物件的所在各呼叫
06/01 02:51, 12F

06/01 02:52, , 13F
delete 一次, 手動個別呼叫建構子也要手動解構物件,
06/01 02:52, 13F

06/01 02:53, , 14F
所以這邊是正規的作法, 通常我就直接呼叫 C lib 函式
06/01 02:53, 14F

06/01 02:54, , 15F
或是 std::allocator 來配記憶體了, 直接在語法上跟新
06/01 02:54, 15F

06/01 02:55, , 16F
的 new operator 做區別
06/01 02:55, 16F

06/01 02:57, , 17F
如果你真的作到把 operator new/delete 都 overload
06/01 02:57, 17F

06/01 02:58, , 18F
或是類別只是簡單的 POD, 那解構子要不要呼叫就看各人
06/01 02:58, 18F

06/01 02:58, , 19F
06/01 02:58, 19F
感謝版主的補充!

06/01 02:59, , 20F
恩恩,我明白了,謝謝版主細心解釋!:D
06/01 02:59, 20F

06/01 03:03, , 21F
我記得 Effective C++ 花蠻大篇幅講這個, 可以看看
06/01 03:03, 21F

06/01 03:24, , 22F
我最近就在念這兩本XDDD 希望能把 C++ 學好 lol
06/01 03:24, 22F

06/01 06:27, , 23F

06/01 06:28, , 24F
可以直接用 new char[]
06/01 06:28, 24F

06/01 11:38, , 25F
good job
06/01 11:38, 25F
透過 char* 跟系統要空間的方法真特別!! 不過要到的空間其實是用 char() 初始化過的 感覺和 uninitialized 不太一樣 ※ 編輯: darkgerm 來自: 140.113.230.123 (06/01 16:12)

06/01 22:38, , 26F
用 char 的原因是為了要能 delete
06/01 22:38, 26F

06/01 22:39, , 27F
如果不用 new / delete 的話直接用 malloc / free 就好
06/01 22:39, 27F
文章代碼(AID): #1FnxIscl (C_and_CPP)
文章代碼(AID): #1FnxIscl (C_and_CPP)