C++列表的内存损坏问题
Posted
技术标签:
【中文标题】C++列表的内存损坏问题【英文标题】:The memory corruption problem of C++ list 【发布时间】:2021-12-16 10:51:14 【问题描述】:我是 C++ 新手,我需要将列表容器用于我的基于 3D 标记的分水岭函数。但是当我使用列表容器时会遇到奇怪的错误。我可以知道我的代码有什么问题吗?
非常感谢!
我使用列表向量来保存等待搜索像素索引。
我是这样声明变量的(GVInt32
就是int32_t
):
vector<list<GVInt32>> toSearchList;
而我使用了list的这两种操作:
-
在列表末尾添加新的等待搜索索引
toSearchList[cnt].push_back(newidx);
-
删除列表中间的搜索元素(
it
是list<GVInt32>::iterator
):
it = toSearchList[cnt].erase(it);
但我得到两种错误:
malloc(): memory corruption
当我这样做时
toSearchList[cnt].push_back(newidx);
当我在调试器中检查变量时,列表末尾出现不可访问的元素:
[Not accessible elements][1]
https://i.stack.imgur.com/flJg3.png
IDE是QT creator 4.15.2
系统是Ubuntu 18.04
完整代码
分水岭_wz.cpp:
#include "watershed_wz.h"
WaterShed_WZ::WaterShed_WZ()
array<GVInt32, 6> WaterShed_WZ::getNeighbor_WZ(const GVInt32 idx, const GVInt32 width, const GVInt32 height, const GVInt32 thick)
GVInt32 SLICE = width * height;
GVInt32 z = idx / SLICE;
GVInt32 y = (idx%SLICE) / width;
GVInt32 x = idx % width;
array<GVInt32, 6> nIndex;
nIndex[0] = (x == 0) ? -1 : (idx - 1);
nIndex[1] = ((x + 1) == width) ? -1 : (idx + 1);
nIndex[2] = (y == 0) ? -1 : (idx - width);
nIndex[3] = ((y + 1) == height) ? -1 : (idx + width);
nIndex[4] = (z == 0) ? -1 : (idx - SLICE);
nIndex[5] = ((z + 1) == thick) ? -1 : (idx + SLICE);
return nIndex;
void WaterShed_WZ::Watershed3D_WZ(
const Mat im,
const GVInt32 width,
const GVInt32 height,
const GVInt32 thick,
GVInt32* label,
const vector<vector<GVInt32>> marker)
//<Parameter>
//<image> the image for watershed
//<width> the width of the image
//<height> the height of the image
//<thick> the thick of the image
//<label> the map to save result. need to allocate memory before use watershed
//<marker> the marker's index
// const GVByte* image=im.data;
auto t0 = chrono::high_resolution_clock::now();
QTextStream out(stdout);
// const GVInt32 SZ_slice = width * height;
// const GVInt32 SZ = SZ_slice * thick;
const GVInt32 markerNum = marker.size();
// create toSearchList. Saved pixel connected to labeled pixels and wait to search
vector<list<GVInt32>> toSearchList;
toSearchList.resize(markerNum);
// set label to INIT (unsearched)
// ::memset(label, -1, sizeof(GVInt32) * SZ);
// initialize
array<GVInt32, 6> nIdx;
for (size_t i = 0; i < markerNum; i++)
for (GVInt32 idx : marker[i])
// initialize label (which can be considered as a map of pointer to labelBar)
label[idx] = i + 1;
nIdx = getNeighbor_WZ(idx, width, height, thick);
for (GVInt32 newidx : nIdx)
if (newidx != -1)
if (label[newidx] == -1)
toSearchList[i].push_back(newidx);
label[newidx] = -2;
//watershed
GVByte h;
GVInt32 idx;
for (int h_cnt = 0; h_cnt < (1+(int)GV_BYTE_MAX); h_cnt++) // water height
h = (GVByte)h_cnt;
for (GVInt32 cnt = 0; cnt < markerNum; cnt++) // for each marker
list<GVInt32>::iterator it = toSearchList[cnt].begin();
while (!toSearchList[cnt].empty())
// for each pixel connected to the cnt-th labeled region
idx = *it;
// if this pixel is higher than water, ignore it
if (im.at<unsigned char>(idx) > h)
++it;
if(it == toSearchList[cnt].end())
break;
else
continue;
// this pixel is lower than water, assign it
label[idx] = cnt + 1;
// L.at<int>(idx)=cnt + 1;
// add new neighbor
nIdx = getNeighbor_WZ(idx, width, height, thick);
for (GVInt32 newidx : nIdx)
if (newidx != -1)
if (label[newidx]== -1)
toSearchList[cnt].push_back(newidx);
label[newidx] = -2;
// L.at<int>(newidx)=-2;
// erase searched pixel
it = toSearchList[cnt].erase(it);
if(it == toSearchList[cnt].end())
break;
else
continue;
auto t1 = chrono::high_resolution_clock::now();
auto dt = 1.e-9 * chrono::duration_cast<std::chrono::nanoseconds>(t1 - t0).count();
out << "Watershed used " << dt << " seconds.\n\n" << Qt::endl;
分水岭_wz.h:
#ifndef WATERSHED_WZ_H
#define WATERSHED_WZ_H
#define _USE_MATH_DEFINES
#include <vector>
#include <array>
#include <list>
#include <opencv2/core.hpp> //basic building blocks of opencv
#include <opencv2/imgcodecs.hpp> // image io
#include <opencv2/highgui.hpp> //image display
#include <QDebug>
#include <QTextStream>
#include <chrono>
using namespace std;
using namespace cv;
typedef unsigned char GVByte;
typedef int32_t GVInt32;
//typedef uint32_t GVInt32U;
const GVByte GV_BYTE_MAX = UCHAR_MAX;
class WaterShed_WZ
public:
WaterShed_WZ();
static array<GVInt32, 6> getNeighbor_WZ(const GVInt32 idx, const GVInt32 width, const GVInt32 height, const GVInt32 thick);
static void Watershed3D_WZ(
const Mat im,
const GVInt32 width,
const GVInt32 height,
const GVInt32 thick,
GVInt32* label,
const vector<vector<GVInt32>> marker);
;
#endif // WATERSHED_WZ_H
【问题讨论】:
不看你的代码,我能看到的唯一问题是 cnt 可能不是一个有效的索引。 用-g
编译并在valgrind
下运行。 valgrind
会准确地告诉您发生了哪些错误的内存操作、在哪一行以及错误访问的内存曾经是什么(在双重释放、释放后使用等情况下)。
【参考方案1】:
尝试像这样删除[cnt]
索引
toSearchList[cnt].end() --> toSearchList.end()
【讨论】:
您好,Omer,感谢您的建议。我正在使用列表向量来保存要搜索的像素。你的意思是我实际上不能用list作为vector的元素? 我使用列表向量,因为我有几个标记,每个标记都需要有自己的待搜索像素列表。以上是关于C++列表的内存损坏问题的主要内容,如果未能解决你的问题,请参考以下文章
挣扎 - 又一个内存损坏问题,错误分配(C++,VS 2008)