全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1659
推到 Plurk!
推到 Facebook!

"operator=" 與 "copy constructor" 在 stack 的佈局

尚未結案
scottish
一般會員


發表:2
回覆:1
積分:0
註冊:2004-04-06

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-10-05 20:07:04 IP:220.135.xxx.xxx 未訂閱
考慮以下程式碼:(參考自侯老大「多型與虛擬」) class CA{ public: int a1,a2; CA(){a1=5, a2=3} CA(const CA &ca){a1=ca.a1;} CA &operator=(const STC &ca){a2=ca.a2;} } CA func(){ CA myca; myca.a1=10; CA yourca = myca; //"operator=" or "copy constructor" or both?? yourca = myca; //"operator=" !! return yourca; //"copy constructor" !! } int main(int argc, char *argv[]) { CA hisca = func(); //"operator=" or "copy constructor" or both?? return 1; } 以上,我的問題在於當喚起"copy constructor"或是"operator="時 記憶體的佈局如何? 1. "operator="的參數,也就是rhs是個參考,而lhs也是個參考,意思就是讀入rhs的參考,經過處理後,回傳給lhs,所以在stack的佈局都是對應到同一個記憶體位置,對嗎? 2. "copy constructor"本身的函式沒有問題,但是在發生"copy constructor"的函式有點疑惑,就是上面的func(),首先,func()再stack宣告一塊記憶體CA給物件yourca,接著對yourca處理過後,再將yourca回傳,yourca在回傳"完畢"之後(何時稱為「完畢」),即從stack移除,而此時透過"operator="的rhs(即func()所回傳的yourca),對lhs進行操作,若以上yourca由stack移除的動作,是在"operator="之前發生,則有可能會產生memory leak,所以,依此推論,"copy constructor"的回傳值會在"operator="之後才從stack移除,可是,我的疑問就是func()被invoked時,其在stack中配置的記憶體,將等到其喚起者(即"operator=")對其處理完後,才會移除,對嗎? 若是如此,所有的function()也都是在其喚起者動作執行完畢才從stack中移除的嗎? 以上是個人推論,有勞諸前輩指點! 謝謝!
pwipwi
版主


發表:68
回覆:629
積分:349
註冊:2004-04-08

發送簡訊給我
#2 引用回覆 回覆 發表時間:2004-10-06 01:41:36 IP:211.76.xxx.xxx 未訂閱
scottish你好: 針對你的問題,在這裡提供一些想法: 1.在這裡Reference的實作,是以pointer完成的。而傳入的參數是放在stack,回傳的的值是放在EAX。另外參數和回傳值所指向的物件實體大部分的時候是不一樣的。 2.如果compiler有進行return value optimization(RVO)。你的問題就完全不能成立了。如果不進行RVO,你可能忽略了return的時候,會有一個暫時的物件被建立。而這個暫時的物件,在func函式結束後還會存在。一直到"CA hisca = func();"這一行執行結束才會被釋放。至於函式裡的區域變數,在return前一定會被釋放。
scottish
一般會員


發表:2
回覆:1
積分:0
註冊:2004-04-06

發送簡訊給我
#3 引用回覆 回覆 發表時間:2004-10-06 04:04:40 IP:220.135.xxx.xxx 未訂閱
感謝版主! 恕弟才疏學淺,再請教幾個問題: 1. EAX是什麼東西啊? How can I find out some information about it?? 是屬於assembly還是屬於CPU register?? (或是請教您,如果我想要再深究這個問題的話,該往哪個領域去找資料) 又,Reference實質上為「型式漂亮的pointer」(引述侯老大的觀點),所以您所說的「在這裡Reference的實作,是以pointer完成的」這點我可以接受,可是,後面這句「參數和回傳值所指向的物件實體大部分的時候是不一樣的」,應該就是您所言的EAX與stack不同之處,是嗎? 2. 您所謂的「暫時的物件」,與我所言的「將等到其喚起者(即"operator=")對其處理完後,才會移除」意思是一樣的嗎? 我的疑問是,這個function是特例吧? 這個「暫時的物件」只有在回傳reference時會被建立,並延伸其原有的scope! 這樣的function call不會發生問題嗎? 如何知道compiler在這之中做了什麼? 又如何知道compiler會自動將其釋放? 這似乎與您所說的RVO有關係! 這是屬於compiler的領域,是嗎? (其實我不是很懂您所謂的「如果compiler有進行return value optimization(RVO)。你的問題就完全不能成立了。」究竟RVO到底做了什麼?跟我的推論差異在哪裡? 不過這應該是我要自己去找資料來study的,只是這些東西我完全陌生,所以沒有方向! 懇請指點一二!) 勞煩您再次指教! 謝謝!
pwipwi
版主


發表:68
回覆:629
積分:349
註冊:2004-04-08

發送簡訊給我
#4 引用回覆 回覆 發表時間:2004-10-06 15:40:02 IP:211.76.xxx.xxx 未訂閱
scottish你好:     你的問題都很切中編譯器的核心和要點,我只能就我所知的來討論,或許其他版友們也能補充一些。    .關於EAX和stack的部分,這個部分是比較屬於組合語言的地方。一般都會放在組合語言教本的最後面,告訴你如何用組合語言來呼叫C的函式、如何得到回傳的值。就我所知(如果我沒記錯的話),C函式的參數是放在stack,而pascal函式的參數是放在register。回傳值的部份,C的回傳值是放在EAX暫存器。(先提一點,EAX是32位元,所以最多只能回傳4個BYTES),pascal的我就忘了...    .在operator=裡,傳入的實際上是一個pointer。pointer"本身"是在stack中,傳回的值是this指標的"值"(你的碼應該少了一行return *this;),這個"值",會被放到EAX中當成傳回值。    pointer"本身"和pointer"指向的位置"在這裡要明確區分開來。pointer本身只是拿來傳遞用而已,實際的CA object並沒有被傳來傳去。    .之前我留的伏筆提到,回傳的值最大只能有4個Bytes。這明顯的存在一個問題:要以return value的方式值回一個8個bytes的物件,怎麼做?C++的解決方法是,回傳前先把要回傳的物件複製一份,(就是我所提的暫時物件),函式結束後這個暫時物件還是存在stack中的,所以之後就可以被當成回傳的物件來取值,取值完後馬上就被delete。    問題解決了,但是這裡付上的效率的代價:代價包含1.產生暫時物件、2.做複製的動作、3.刪除暫時物件。這個代價可不小,因此隨後解決的方案就被提出來,叫做return value optimization。如果這個方法運用到你原來的程式碼,就會看起來像這樣子:  
void func(CA& yourca)
{
  CA myca;
  myca.a1=10;
  yourca = myca;
}    int main(int argc, char *argv[])
{
  CA hisca
  func(hisca);
}     
其中要被傳回的物件,反而先被當成一個reference參數傳給函式,因此就可以少一個暫時物件的生成。就我所知,BCB6好像在debug模式下就會做這樣的最佳化。至於compiler什麼時候會套用RVO,什麼時候不會,完全看compiler的功力。所以這個問題比較難討論.... 尤其在BCB6出品的時候,compiler做的很好,這類最基本的最佳化都有做到(就算是切換在debug模式下)。因此你提到的回傳值的問題,大部分就被compiler的最佳化給做掉了,而且編出來的組合語言也和原本程式的expression差很多。 所以,就實際上的運作而言,很難討論這個議題....如果想了解的真正的運作的方式,只能打開在debuger中的反組譯碼,一個一個的切敲了。
系統時間:2024-09-07 9:00:01
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!