为什么在返回对象Mat时会出现堆损坏?

时间:2013-03-11 02:24:31

标签: c++ visual-c++ opencv heap-corruption

我不明白为什么我用这个程序弄错了堆错误(我在类Mat上使用OpenCV):

class A {
    private:
    Mat image;      

    static UINT ThreadProc( LPVOID pParam ) {
        A* pThis= (ClientNetwork*)pParam;
        UINT nRet= pThis->DoThreadProc();     // get out of 'static mode'
        return( nRet );
    }
    UINT ClientNetwork::DoThreadProc() {
         vector<uchar> vect;
         while(1) {
             /**** initialize vect and get the image data to decode ****/

             decode(vect);
         }
    }

    public:
    void decode(const vector<uchar>& vectorData){image=imdecode(vectorData, CV_LOAD_IMAGE_COLOR);}
    Mat get_image(){return image;}
    void start() {m_pcThread= AfxBeginThread(ThreadProc, this );}
}

int main() {
    A* a = new A();
    a->start();
    while(1) {
        Mat image = a->get_image();
    }
    delete a;
    return 0;
}

似乎错误来自Mat image = a->get_image();,因为如果我返回引用而不是对象的副本,我就不再有错误了:

Mat* get_image(){return &image;}

Mat* image = a->get_image();

我读到,返回一个对象的副本在C ++中比引用更优雅。所以我想知道出了什么问题。

编辑:Visual Studio在a->decode(vect)中断,但只有在我返回一个对象而不是一个引用时才会发生。

编辑2: 我编辑了代码以反映完整的程序。我认为问题来自共享对象a,它同时被复制和修改。我将使用互斥锁查看问题是否仍然存在。

3 个答案:

答案 0 :(得分:2)

您使用a而不进行初始化。

int main() {
    A* a;
    vector<uchar> vect;
    while(1) {
        // get the vector of data
        a->decode(vect);

欢迎来到未定义的行为,人口:你。

初始化a以获得更好的结果。

答案 1 :(得分:2)

然后就是你自己建议的线程同步问题。图像在无限循环中不断填充。在它的中间,你试图复制它。灾难食谱。在每次迭代中,您需要在DoThreadProc中的该循环内部进行写入锁定。然后你需要在你的get_image中取一个读锁。您需要使用不会使读者厌烦的读/写锁定库。

或者,您可以使用互斥锁/关键部分。写入循环和读取(get_image)只是在他们正在工作时获得对图像的独占访问权。

我很好奇 - 你的线程程序在无限循环中解码事物。你想在那里做什么?在阅读你期望的图像时?循环迭代中那个时间点的任何图像?

答案 2 :(得分:1)

cv::Mat的复制构造函数不会创建图像的深层副本。它只是创建对原始Mat的引用并增加其引用计数。 在类的以下函数中,return语句调用复制构造函数,返回对原始image的引用,这是堆损坏的可能原因:

Mat get_image(){ return image; }

您应该按如下方式返回image的深层副本,以便不会意外修改原始image

Mat get_image(){ return image.clone(); }