问题删除2D动态数组在C ++(其最终存储在载体中)
-
11-09-2019 - |
题
所以,我有我想,当我用它做以释放其内容这个二维动态数组。但是我一直运行到析构函数后堆损坏。该代码工作正常(当然内存泄漏),如果我注释掉析构函数。 (Visual Studio 2005中)
FrameData::FrameData(int width, int height)
{
width_ = width;
height_ = height;
linesize[0] = linesize[1] = linesize[2] = linesize[3] = 0;
// Initialise the 2d array
// Note: uint8_t is used by FFMPEG (typedef unsigned char uint8_t)
red = new uint8_t* [height];
green = new uint8_t* [height];
blue = new uint8_t* [height];
for (int i=0; i < height; i++)
{
red[i] = new uint8_t [width];
green[i] = new uint8_t [width];
blue[i] = new uint8_t [width];
}
}
FrameData::~FrameData()
{
// Delete each column
for (int i=0; i < height_; i++)
{
delete[] ((uint8_t*) red[i]);
delete[] ((uint8_t*)green[i]);
delete[] ((uint8_t*)blue[i]);
}
// Final cleanup
delete[] red;
red = NULL;
delete[] green;
green = NULL;
delete[] blue;
blue = NULL;
}
我不知道什么是错的代码。唯一的另一件事是别的地方,我这样做在一个循环崩溃发生的位置
FrameData myFrame;
std::vector<FrameData> frames;
...snipped...
frames.push_back(myFrame);
这不应引起任何问题,对不对?如果我记得正确的,使的push_back而不是存储指针或引用的副本。
PS。是的,我应该用向量。但我不能。
附加信息:
操作员=和拷贝构造没有限定。我想这是针对该问题的原因。
解决方案
您的问题是,你猜在这里:
FrameData myFrame;
std::vector<FrameData> frames;
...snipped...
frames.push_back(myFrame);
在矢量使您在推的元素的副本。你有什么你的拷贝构造函数和/或operator=
为你的类?如果你没有定义,编译器会为您创建默认版本只是使你的类成员的副本。这将指针成员red
,green
和blue
复制到新的实例。然后您复制时,它超出范围就会被破坏,从而导致指针旧实例被删除。然后复制到载体的一个将具有无效指针自从指针的目标因此删除。
一个好的经验法则是,如果您有任何原始指针的成员,那么你需要做一个拷贝构造函数和operator=
将正确处理这种情况下,通过确保指针被赋予新的价值,而不是共享,或所有权在实例之间转移。
例如,在std::auto_ptr
类有一个原始指针 - 拷贝构造的语义是将指针的所有权转移到目标
在boost::shared_ptr
类有一个原始指针 - 语义是通过引用计数的装置共享所有权。这是处理包含指向你的类std::vectors
的好方法 - 共享指针将控制所有权为你
的另一种方式可以是使用载体把你的构件指针的位置 - 的构件指针简单地为您的阵列别名无论如何,所以该载体是一个很好的替代
其他提示
除非你有一个深拷贝构造函数和赋值操作符的FrameData类我的直觉是,编译器生成的拷贝构造函数用的push_back使用。自动生成的拷贝构造函数和赋值操作符会做一个成员复制,这将导致浅表副本在这种情况下。不幸的是你的析构函数不知道的副本,以便在复制过程中,有一个很好的机会,FrameData的临时副本被破坏,这将需要所有的数据吧。
在该过程再次调用以后,析构函数将导致双自由,加上其他的分配可能已经使用“自由”存储器的一部分。这看起来像从这里一个很好的理由堆损坏。
找到的问题,像这些通常是使用一个工具,如Valgrind的或纯化以查明问题的最佳方法。
<击>这不是一个问题的答案击>,只是一个观察。
由于您的帧数据可能会很大,以避免过多的复制,可能是更好的为你使用
std::vector<FrameData *> frames;
编辑: 正如其他人所指出的那样,这也将解决你的问题,崩溃
您即将进行的push_back一份正确的,但FrameData有一个合适的拷贝构造函数和赋值操作符?
另外,为什么剧组在这里:
delete[] ((uint8_t*) red[i]);
在C ++中,如果你必须使用C风格(或重新解释)投,代码几乎可以肯定是错误的。