R6025 -pure virtual function call

作者在 2011-02-02 19:31:10 发布以下内容
前几天遇到了传说中的R6025错误,经过网络上搜索一番知道这是由于运行时调用了鸡肋的纯虚函数,一般出现在构造函数和析构函数中间接的调用了纯虚函数。但问题是,这不是我的情况。因此,我进行了两天的代码调试,总算是发现了元凶。
 
问题出在完成端口!在我的完成端口模型中,完成键是一个对象,它随一个SOCKET句柄关联到完成端口。当一个完成包被成功获取,则使用这个完成键(对象)执行完成任务。这没错,并且我把对象使用引用计数来管理生命周期,一切尚在预期之中。但问题出在,我需要更换这个SOCKET句柄的完成键。当这个SOCKET需要收发数据,则被封装在一个叫NetSession的类中,完成键就是这个NetSession,收发的处理就由NetSession来完成。而当这个SOCKET需要重用时,就需要另外一个对象来处理,因此在调用DisconnectEx之前,我必须改变完成键,使之能处理DisconnectEx的完成包。在此之前,我已经释放了NetSession对象(引用计数已经为0),但SOCKET被保留待重用。我对这个SOCKET进行了重新关联完成端口,并使用了能处理DisconnectEx的对象为完成键。这就悲剧所在,我在重新关联完成端口时得到了87错误!而我则选择了忽略了它!结果这个SOCKET调用了DisconnectEx,而在处理完成包的则是那个已经释放的NetSession!!R6025!!
 
解决这个问题,目前只有两个想法(不是方法):
1、找到能够重新关联完成端口的方法。
2、重叠结构是一个突破口。
 
希望在下一年伊始能够解决问题。。。
winsock+icop | 阅读 16405 次
文章评论,共1条
迷失的木桶(作者)
2011-02-03 20:58
1
我已经放弃使用完成键,这绝对折磨人。一个已经关联到完成端口 SOCKET ,不能再改变绑定的完成键。虽然有变通的方法可以改变完成键,但是在我的程序结构上就会造成很大的变动。<br />
<br />
struct CompletionKey<br />
{<br />
&nbsp; &nbsp;void*&nbsp; &nbsp;context;<br />
};<br />
<br />
上面这个结构就是变通的完成键结构,当一个 SOCKET 与一个 CompletionKey 一起关联到完成端口后,可以修改 CompletionKey 中的 context 字段,这就变相的改变完成键值。但是,问题是一个已经关联过完成端口的待重用的 SOCKET 在关联完成端口时,不管是关联到原先的完成端口还是关联到一个新的完成端口,都会返回 87 错误!也就是说它仍旧关联在第一次关联的完成端口。这样,我很纠结。一个已经关联过的 SOCKET 有一个对应的 CompletionKey ,我不能丢弃这个 CompletionKey,否则当这个 SOCKET 被重用后所有的重叠操作通过完成端口返回的还是这个 CompletionKey。总之,这个SOCKET已经和CompletionKey形影不离了。如果有一个对SOCKET封装的类,该类不能区分这个SOCKET是新的,还是已经关联过完成端口。那么在构造该类对象时还要提供一个与这个 SOCKET 伴随的 CompletionKey,对新的SOCKET来说这是多余的。这实在是很糟糕。<br />
<br />
幸运的是还有一个结构可以替代完成键,那就是 OVERLAPPED 。《windows 网络编程》中称其为单I/O操作数据(PER_IO_DATA),这个名字自从第一次看到就觉的很别扭。我比较喜欢把一个 OVERLAPPED 称为 Task ,这样从完成端口出队一个完成包就是完成了一个 Task。在 Task 结构中增加一个完成键根本不是问题,所有问题都迎刃而解!
游客请输入验证码
最新评论