这里主要遇到两个错误,都是粗心吧
POSITION pos = NULL;
BOOL bNewUser = TRUE;
for (pos = m_UserList.GetHeadPosition(); pos!=NULL;) //遍历链表
{
CUserInfo* pUserInfo = (CUserInfo*)m_UserList.GetNext(pos);
if (pUserInfo->m_strName == userInfo.m_strName) //如果是已经注册的用户
。。。。。
{
public:
fun()
{
std::cout<<"Just For Fun"<<std::endl;
}
};
int main()
{
A *pA = NULL;
pA->fun();
return 0;
}
//停止发送
ShutDown(1);
//移除在线列表
m_pServer->RemoveChatter(this);
//删除自身
delete this;
}
1.
BOOL CServerDlg::VerifyUserAndUpdateUserList(CUserInfo& userInfo, CClientSocket *pClient)
{
POSITION pos = NULL;
BOOL bNewUser = TRUE;
for (pos = m_UserList.GetHeadPosition(); pos!=NULL;) //遍历链表
{
CUserInfo* pUserInfo = (CUserInfo*)m_UserList.GetNext(pos);
if (pUserInfo->m_strName == userInfo.m_strName) //如果是已经注册的用户
。。。。。
在红色标记出报错,刚开始一直以为是m_UserList出了问题,纠结了好一会,然后发现在调试窗口中this指针和m_UserList中的内容都是非法的。
这个时候就更迷茫了,一个成员函数内部this指针都是无效的,这又当从何说起额。其实当时还是有点犯浑,把成员函数的调用和成员变量的调用都当成是由this指向而使用的了。之后才想起向上跟踪,然后到了上一级函数CServerDlg::ProcessPendingReceive 再往上看,找到了CClientSocket::OnReceive 在该函数中,通过 m_pServerDlg->ProcessPendingReceive()。按理说,这里的ProcessPendingReceive中的this指针就是m_pServerDlg。然后在调试窗口验证果然:
之后就简单了 m_pServer的非法值是因为我在服务器接受到一个新的连接时,创建客户端套接字类时,忘了传入服务器的this指针。而恰好CClientSocket有这样一个默认构造函数,并且我没有在里面给m_pServer赋空(其实即使赋空函数仍然会调用,只是在使用成员时,能更精准地定位错误)。
测试了一下这段代码
#include <iostream>
class A
{
public:
fun()
{
std::cout<<"Just For Fun"<<std::endl;
}
};
int main()
{
A *pA = NULL;
pA->fun();
return 0;
}
能够进一步的确认c++类成员函数和普通函数的唯一区别就是隐藏一个this指针,成员函数通过this指针来操控对象数据,并且由于作用域的原因,该成员函数能够操作类私有成员。除了作用域限制和this指针之外,成员函数和普通函数是一样的。这也能解释为什么成员函数并不占用对象内存,因为它们都放在类里,它们属于类,这里的属于类就是一种作用域限制,而对象想要调用该函数,比如 a.fun(); pA.fun() 都会转换为fun(&a)和fun(pA),然后像普通函数一样调用成员函数。这个this指针唯一标识对象,因此函数不需要放在对象里,所有的对象可以共享一份函数代码。
错误总结:主要是粗心,还有对指针不够重视,如果当时在无参构造函数里面将m_pServer赋为NULL 即使当时粗心没有传入参数,也不会因为this指针为cdcdcd而浪费时间。当然将指针赋为NULL的好处远不在这里,而在于对进一步的未知数据修改进行拦截,还有就是便于在其他函数中通过ASSERT很方便的判断指针是否有效,只要你能够确保无效的指针都被赋NULL了。那么通过ASSERT(p != NULL)的p指针就基本不会有安全问题
错误二:
这个错误也困扰了一些时间,主要之前没有见过这一类型的错误,
在用户下线时,出现这个错误。进行调试定位 到以下几句
void RemoveChatter(pClient)
{
............
//广播更新后的列表
SendUserListToAllChatter();
//移除在线列表
if((pos = m_ChatterList.Find(pClient)) != NULL)
m_ChatterList.RemoveAt(pos);
SendUserListToAllChatter();
//移除在线列表
if((pos = m_ChatterList.Find(pClient)) != NULL)
m_ChatterList.RemoveAt(pos);
..............
}
然后发现SendUserListToAllChatter里面会报错,就一股脑杀进去鼓捣了大半天,结果大败而归。由于不知道这个错误提示是什么东东,连文件加载和保存都检查过了。到最后才意识到:在RemoveChatter的调用处,也就是CClientSocket的OnClose处,有如下如语句:
void CClientSocket::OnClose(int nErrorCode)
{
//停止发送
ShutDown(1);
//移除在线列表
m_pServer->RemoveChatter(this);
//删除自身
delete this;
}
才开始有点眉目,ShutDown函数的调用就表示该CClientSocket类不再发送数据了。而在RemoveChatter中,我是先发送后移除的,也就是说,发送的时候发送到了被移除的那个客户端类那里,而该类已经ShutDown()了 因此就出现了以上错误。而由于在SendUserListToAllChatter中的迭代只有某一次会出错,也就没有跟踪到。
改正方法只需要将上面两句交换:
//移除在线列表
if((pos = m_ChatterList.Find(pClient)) != NULL)
if((pos = m_ChatterList.Find(pClient)) != NULL)
m_ChatterList.RemoveAt(pos);
//广播更新后的列表
SendUserListToAllChatter();