OpenCV对象析构时错误
!!!!还是没有找到问题所在!!!!
一个非常奇怪的问题
这几天在调试自己“抄写”ORB_SLAM代码时遇到的非常奇怪的问题。主要发生在各种对象的析构时,比如cv::Mat
,std::vector<cv::Keypoint>
等等。这些对象的析构时机不同,但不外乎有下面这几种:
- 离开函数作用域时
- 对象被销毁时(类对象内有成员是
cv::Mat
或者容器内的元素是opencv对象时) - 手动调用容器的
clear
方法时
当这些时刻发生,程序经常会漰溃,用gdb查看core文件查找漰溃的代码时,基本都发生在下面的时刻:
cv::Mat
析构时,调用了cv::Mat::release()
方法std::vector<cv::Keypoint>
析构时或者其他stl容器析构时,会调用容器内元素的析构函数std::vector<xxx,stl::alloc<xxx>>::deallocate
的时候
一开始以为是各种对象没有被初始化,所以导致析构时错误。但是后面各种对象都补上了初始化,依旧会存在析构时错误。几经折腾,终于摸清了问题所在。
启发
能够搞清楚这个问题主要受到下面这篇文章的启发opencv+vs2015 堆内存析构异常
首先,要知道,opencv的默认的编译都是动态库编译,opencv要编译成静态库十分困难,特别是里面的视频部分,由于要避免开源协议,在编译成静态库时会去掉视频模块。所以,opencv的默认编译方式是动态库。
然后opencv会链接一些静态库,这样就导致了opencv内部拥有一个所谓的local heap,如果我们在程序中声明一些对象,但是没有在程序中进行初始化,然后直接调用opencv的一些接口,让这些对象在opencv内部进行初始化,就会导致这些对象是存放在opencv的local heap中,而不是我们程序的堆中。这样就导致了我们在程序中调用析构函数时,会出现错误。
解决方法
知道上面的原因其实解决方法就比较简单,只需要在声明opencv对象的时候同时进行初始化或者更准确地说,是分配内存。注意,这里不单普通对象要进行初始化,比如容器内包含opencv类型的对象也要进行内存分配,即先调用reserve方法分配好容器的内存。
例子1
对于cv::Mat
对象,我们可以这样声明:
1 | cv::Mat img = cv::Mat(); |
出错用例:
1 | cv::Mat img = cv::imread("xxx.jpg"); // 此时img的内存是在opencv内部申请的 |
例子2
对于std::vector<cv::Keypoint>
对象,我们可以这样声明:
1 | std::vector<cv::Keypoint> kps; |
出错用例:
1 | std::vector<cv::Keypoint> kps; |