项目实现中遇到最多的麻烦就是指针造成的各种程序崩溃,当然这些问题现在都一一解决,libevent-1.4.3中的http相关的测试用例全部通过。但是这并不能保证代码一定正确,因为指针的存在,还是有程序崩溃的可能。所以总结了解决bug过程中的如下经验:
对于这一点,一个惨痛的经历就是由于不确定性造成的程序崩溃的问题,比如class中有一个函数指针cb,如果没有在声明时初始化为nullptr,那么使用g++5.4的编译器随机给cb一个值,但是不一定为0,所以很可能在之后判断cb的时候不为空,然后调用,然后崩溃(gg)。 这个问题在高版本的编译器如g++7.3中有可能不会出现,但是又可能出现其它的问题,所以最直接的方式就是一定要将未使用的指针声明为nullptr
虽然理论上来说delete this 在有些情况下是可以存在的,但是非常可能因为控制流的不清晰而导致不可名状的问题,所以资源类一定要由资源管理类进行释放。这里比如server使用list管理着几个连接,那么就应该由server来进行连接的创建和释放
智能指针能够方便的解决资源泄露问题,而且尽可能多的使用智能指针也能够避免很多可能出现的指针问题,但是智能指针需要注意的是避免资源的多次释放,需要注意的就是析构函数中避免多次删除和释放,避免double free.
对于这样的错误调试,简单粗暴的方式就是使用gdb在可能出错的多个析构函数处打断点,然后c到最后一个出错的地方,之后不断单步调试,最后会停在出问题的地方。这种方式要注意的问题就是一定要在开始单步调试之前尽可能的靠近崩溃的地方,因为不这样的话step很容易陷入c++密密麻麻的各种标准库函数中去了。
在http连接的实现中,被一个问题困扰了好久,首先http_connection的实现是继承自buffer_event,管理着一个文件描述符,这个文件描述符被buffer_event的读写事件rw_event所拥有,在对象析构的过程rw_event会close(fd),那么问题来了,http_connection在关闭连接时会调用close(fd),这样就会进行两次fd的关闭,在server的执行中会给客户端的连接造成一个connection reset的错误。
解决的方案非常简单,在fd关闭时,一定要将其置为-1,并在调用close之前判断fd是否为-1,这样就能避免资源的重复释放。