一、问题描述
因为最近在学习 C++ 并实践导师给的项目,在实践的过程中基本每天都会踩坑,今晚遇到了一个困扰了我好几个小时的问题。具体问题是当程序运行时总会报 pure virtual method called terminate called without an active exception 这个错误。
对于这个问题我在网上查询了很多资料都没有太好的解决方案,对于我的业务代码基本是这样的:
void func()
{
while(true)
{
connfd = accept();
CWork work;
work.setConnfd(connfd);
m_thread_pool.addWork(work);
}
}
void f()
{
work.run();
}
主要的代码逻辑就是前端接收 TCP 请求,将其封装为 CWork 后交给线程池来进行处理(具体是将其添加到任务队列中,然后又业务线程从任务队列中不断获取任务执行)。
二、解决思路
首先在网上经过查询后我发现这个错误的主要原因是当前对象已经被销毁或者正在被销毁,导致最终调用到其基类的 虚方法 上,最终报出了这个错误。为了验证这个思路我首先在该对象(work)的析构函数中进行了打印,在运行时果然发现在执行到 work 对象的 run 方法之前该对象就已经被销毁了。
后来我又做了很多尝试,最终才发现因为自己对于 C++ 语法不熟练,导致对于对象作用范围的判断出现了失误。在 C++ 中我们主要有三种创建对象的方法:
- Test test1; // 栈中分配 ,由操作系统进行内存的分配和管理
- Test test2 = Test; // 栈中分配 ,由操作系统进行内存的分配和管理
- Test *test3=new Test(); // 堆中分配 ,由管理者进行内存的分配和管理,用完必须delete(),否则可能造成内存泄漏
而我上面的那种创建方式刚好就是第一种方式,也就是说当前对象在栈中进行分配的,且因为其作用于为 while 循环中,所以每一轮循环都会创建一个新的 work 对象,且前一个对象因为被保存在栈上,所以循环结束后就已经被销毁。因此,这时再在外部对其进行调用,肯定就会报错了。
三、解决方案
知道了问题出现的原因,对于问题的解决就比较简单了,因为我的项目是针对网络连接请求的,因此必须保证每一个连接都对应一个新的 work 对象,但是我们还需要保证它不会在本轮循环结束后就被销毁。因此,我们直接使用第三种创建对象的方式 Test *test3=new Test()
即可解决该问题。