看板CompBook
标 题网际网路四大服务 答客问 (1) - reference and delete
发信站清华资讯(枫桥驿站) (Sat Mar 25 22:41:21 2000)
转信站Ptt!bbs.ee.ntu!freebsd.ntu!news.cs.nthu!maple
网际网路四大服务 答客问 (1) - reference and delete
侯捷
[email protected]
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: [email protected]