为什么在返回对象时堆损坏?

Why heap corruption when returning an object Mat?

本文关键字:损坏 对象 返回 为什么      更新时间:2023-10-16

我不明白为什么我得到一个损坏的堆错误与这个程序(我使用OpenCV类Mat):

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,它同时被复制和修改。我将看看使用互斥锁是否还会出现这个问题。

使用a而不初始化。

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

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

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

那么这就是线程同步问题,正如你自己所建议的。图像在无限while循环中不断被填充。在它中间的某个地方,你试图复制它。灾难的配方。在每次迭代中,您需要在DoThreadProc的循环中使用写锁。然后你需要在get_image中取一个读锁。您需要使用一个读写锁库,它不会使读取器饿死。

也可以使用互斥锁/临界区。写循环和读(get_image)都在执行工作时独占访问image。

我很好奇-你的线程过程是解码的东西在一个无限循环。你在里面想干什么?在阅读时,你期望看到什么样的画面?在循环迭代的那个时间点有图像吗?

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

Mat get_image(){ return image; }

您应该返回image的深层副本,如下所示,以便原始image不会被意外修改。

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