C++BUG小记——自己写的库都是雷

来源:互联网 发布:邮箱注册淘宝流程 编辑:程序博客网 时间:2024/05/22 00:35

BUG描述

环境

C++ 14Visual Studio 2017zMatrix

描述

zMatrix是我自己造的图像处理的轮子,这几天想着在上面实现一个3层的神经网络识别手写数字,完成之后进行适当的优化,问题出在这里。
_Matrix 作为库的基础,是用来存放图像的,期初没有考虑作为容器来存放任意类型。在实现nn过程中,需要用到序列容器,我用了vector,但是vector并不能进行线性代数运算,但是_Matrix是可以进行基础类型的运算的,所以我把_Matrix适当修改,让它支持_Matrix类型的运算,并且支持使用_Matrix初始化

auto m = vector<vector<_Matrix<double>>>();// 改为auto m = _Matrix<_Matrix<_Matrix<double>>>(2, 1, 1, _Matrix<_Matrix<double>>(2, 1, 1))

起初我用Release模式跑的没有问题,准确率在90%以上,但是最后我用Debug模式跑的时候出问题了,不到10%。
问题出在对数据进行更新的时候,对m中的第一个数据读写没有问题,但是对第二个读写的时候就不对了,单步跟踪也没看出个所以然。
然后我就写了一个测试demo

default_random_engine random_engine(time(nullptr));uniform_real_distribution<double> real_distribution(-1.0, 1.0);// 使用随机数初始化auto www = _Matrix<_Matrix<_Matrix<double>>>(2, 1, 1, _Matrix<_Matrix<double>>(2, 1, 1, _Matrix<double>(2, 1, 1, make_pair(random_engine, real_distribution))));for(auto& ww : www) {    for(auto & w: ww) {        auto v = w;        w = w - w;    }}

如果有数据操作w = w - w;里层第二遍读出的数据就不对了,如果没有数据操作就不会有问题。
我一直怀疑是数据操作过程中是不是有溢出之类的指针操作错误,但是发现操作过程和写入过程都没有问题。
为了定位到哪一步破坏了数据,修改demo

    default_random_engine random_engine(time(nullptr));    uniform_real_distribution<double> real_distribution(-1.0, 1.0);    auto www = _Matrix<_Matrix<_Matrix<double>>>(2, 1, 1, _Matrix<_Matrix<double>>(2, 1, 1, _Matrix<double>(2, 1, 1, make_pair(random_engine, real_distribution))));    auto& w11 = www.at(0).at(0);    auto& w12 = www.at(0).at(1);    auto& w21 = www.at(1).at(0);    auto& w22 = www.at(1).at(1);    for(auto& ww : www) {        for(auto & w: ww) {            auto v = w;            w = w - w;        }    }

这样可以监听到每个数据在每一步运算过程中的变化。发现在运算过程中没有问题,数据错误发生在离开第一次循环进入第二次循环的时候。F**K.
调试了几遍之后,还是没有问题,然后我发现这样初始化容器中的数据是相同的,不太方便,我改成不同的数据方便查看。

    auto www = _Matrix<_Matrix<_Matrix<double>>>(2, 1, 1, _Matrix<_Matrix<double>>(2, 1, 1));    auto& w11 = www.at(0).at(0) = _Matrix<double>(2, 1, 1, 0.1);    auto& w12 = www.at(0).at(1) = _Matrix<double>(2, 1, 1, 0.2);    auto& w21 = www.at(1).at(0) = _Matrix<double>(2, 1, 1, 0.3);    auto& w22 = www.at(1).at(1) = _Matrix<double>(2, 1, 1, 0.4);    for(auto& ww : www) {        for(auto & w: ww) {            auto v = w;            w = w - w;        }    }

改为这样之后,更让我奇怪的事情出现了,为什么第三个和第一个数据相同,第四个和第二个数据相同?然后从赋值的地方初始化,发现,第三个赋值时,第一个数据同样被赋值了。查到地址,发现,两个数据的地址是相同的。
这下明确了,问题出在定义www初始化的时候。
最后发现,问题出在,_Matrix类使用引用计数管理内存,拷贝为浅拷贝,用一个_Matrix初始化一个容器,容器中的_Matrix数据指向的内存是相同的一块。

Fix

针对_Matrix进行特化。

原创粉丝点击