網際網路四大服務 答客問 (1) - reference and …
網際網路四大服務 答客問 (1) - reference and delete
侯捷 jjhou@ccca.nctu.edu.tw
2000.03.25 第一次發表於
清大.楓橋驛站(140.114.87.5).電腦書訊版(Computer/CompBook)
本文將於日後整理於 侯捷網站
侯捷網站:www.jjhou.com
----------------------------------------------------------------
sammy wu wrote (2000/3/9) :
>候老師您好,
>
> 日前閱讀 "網際網路親手打造四大服務" 一書.
> 在第二章 p45 發現一問題..
> 在 BasicServiceThread 函式中,
>
> Line0085 Win32TCPEnv &Env = pStub->m_Env;
> ....
> 但隨即 delete pStub;
>
> 學生想問的是, 前面是 just 宣告 reference,
> 如果作了 delete pStub, Env 還存在嗎??
>
> 還是我觀念出了問題 ?
>
> anyway,感謝老師百忙中檢視我的疑問.
侯捷回覆:
1. 我姓「侯」,不姓「候」
2. 為什麼你不問原作者 :(
3. 好吧,我代打 :)
首先我要說,家俊的這本書涵蓋了一個不小的 library。
其間細節多如牛毛,我無法就 library 的細節部份回答你。
這方面還是請你問作者王家俊先生(他的 email addr 在其序文最後)
但我可就 local 的範圍來檢視你的觀念和你的問題。寫個測試程式,
其中變數名稱皆模仿 p45:
#include <iostream>
using namespace std;
class CWin32TCPEnv
{
public:
// ctor
CWin32TCPEnv(int i1, int i2)
: m_i1(i1), m_i2(i2)
{ }
// copy ctor
CWin32TCPEnv(const CWin32TCPEnv& Env)
: m_i1(Env.m_i1), m_i2(Env.m_i2)
{
cout << "CWin32TCPEnv copy ctor \n";
}
void show() { cout << m_i1 << ' ' << m_i2 << endl; }
private:
int m_i1, m_i2;
};
class CClientStub
{
public:
CClientStub(int i1, int i2)
: m_Env(i1, i2)
{ }
// public data member
CWin32TCPEnv m_Env;
};
void BasicServiceThread(void* lpArg)
{
CClientStub *pStub = (CClientStub *)lpArg;
CWin32TCPEnv &Env = pStub->m_Env;
Env.show(); // 9 28 (5)
delete pStub;
// 這裡測試 Env 還在否
Env.show(); // 7802592 6618664 亂碼,資料不在了! (6)
}
int main()
{
CClientStub *pStub = new CClientStub(9, 28);
CWin32TCPEnv &Env1 = pStub->m_Env; // (1)
CWin32TCPEnv Env2 = pStub->m_Env; // CWin32TCPEnv copy ctor (2)
Env1.show(); // 9 28 (3)
Env2.show(); // 9 28 (4)
BasicServiceThread(pStub);
Env1.show(); // 7802592 6618664 亂碼,資料不在了! (7)
Env2.show(); // 9 28 (8)
}
每行註解都代表其輸出。註解後的編號是為了解說方便。
如你所見,(1) 是 reference,其 assignment 動作並沒有喚起 copy ctor。
程式進行至 (5),資料還在。delete 之後,(6) 顯示,資料已被破壞了。
(7) 受到 pass by pointer(或說 pass by reference)的影響,
資料也遺失了。
純粹從技術的角度來探討,我們有辦法讓資料不遺失。辦法是
攔截 delete pStub; 使它落到我們的控制之中。也就是說
在 class CClientStub 內將 operator delete 多載化,如下:
class CClientStub
{
public:
...
static void operator delete(void *rawMem, size_t size) { }
...
};
正常情況下它應該做點額外處理,然後將記憶體釋放。但現在
這個 operator delete 什麼都沒做,因此記憶體不會被釋還。
增加這個 operator delete 之後,上述程式的 (6)(7) 輸出就
不再是亂碼,而是 9 28(正確值),表示資料還在。
operator delete 和 operator new,可在 "Effective C++" item5~10
獲得豐富的說明和示範。
但以上純粹只是技術探討,應該沒有人會多載化 operator delete 之後
故意不釋放記憶體。我相信家俊也不會這麼做(此刻我沒有時間去 trace
他那麼大一個 library)。
既然我認為不會那麼做,那麼,程式不就有問題了嗎?於是我再往前一步,
看看 library 之中是誰在呼叫 BasicServiceThread(),我發現是 p47 的:
CClientStub *pStub = new CClientStub(...);
....
HANDLE theClient = ::CreateThread(NULL, 0,
::BasicServiceThread, pStub,
0, &ClientThreadId);
換句話說 BasicServiceThread 被用來做為 thread function,
而非如一般函式被直接叫用。thread functions 和一般 functions 有什麼
差異嗎?特別是在引數傳遞方面?我查了 Jeffrey Richter 的
Advanced Windows 3/e, p.82,此處對 CreateThread 的每一個參數
解釋非常詳細。我看不出來 therad function 在引數傳遞方面
和一般函式有什麼差異之處。
所以,看起來,家俊這個 library 在此有點問題。但這是一個
得過大獎的程式,被 CMP Net 的 TechWeb News 選為全球六大
source free 軟體之一(見該書 p303)。所以,是不是有什麼
我沒有看到注意到的地方?
anyway,這個問題頗有趣,我會把此 Q/A 轉給家俊。他目前正在
服役,我不知道何時才會獲得他的回音。
-- the end
--
※ Origin: 楓橋驛站<bbs.cs.nthu.edu.tw> ◆ Mail: jjhou@ccca.nctu.edu.tw
討論串 (同標題文章)
CompBook 近期熱門文章
PTT數位生活區 即時熱門文章