简体   繁体   English

在C ++中删除2D动态数组(最终存储在向量中)时出现问题

[英]Problems deleting a 2D dynamic array in C++ (which is eventually store in a vector)

So I have this 2d dynamic array which content I want to free when I am done with it. 所以我有这个二维动态数组,当我完成后,我想释放它的内容。 However I keep running into a heap corruption after the destructor. 但是我在析构函数之后一直遇到堆损坏。 The code works fine (of course with memory leaks) if I comment out the destructor. 如果我注释掉析构函数,则代码可以正常工作(当然会发生内存泄漏)。 (Visual Studio 2005) (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;    
} 

I have no idea what is wrong with the code. 我不知道代码有什么问题。 The only another thing is somewhere else, I did this in a loop where the crash occurred 唯一的另一件事是其他地方,我是在发生崩溃的循环中完成此操作的

FrameData myFrame;
std::vector<FrameData> frames;
...snipped...
frames.push_back(myFrame);

This shouldn't be causing any problem, right? 这应该不会造成任何问题,对吗? If I remember correct, push_back makes a copy instead of storing a pointer or a reference. 如果我没记错的话,push_back会进行复制而不是存储指针或引用。

PS. PS。 Yes, I should use vectors. 是的,我应该使用向量。 But I am not allowed to. 但是我不被允许。

Additional Info: 附加信息:

The operator= and copy constructor are not defined. 没有定义operator =和copy构造函数。 I guess that's a reason for the problem. 我想这就是问题的原因。

Your problem is as you guessed in here: 您的问题就是您在这里所猜到的:

FrameData myFrame;
std::vector<FrameData> frames;
...snipped...
frames.push_back(myFrame);

The vector makes copies of the elements that you push in. What do you have for your copy constructor and/or operator= for your class? 该向量可复制您要推入的元素的副本。您的类的副本构造函数和/或operator=有什么用? If you have none defined, the default version that the compiler creates for you simply makes copies of the members of your class. 如果未定义,则编译器为您创建的默认版本将简单地复制类成员。 This will copy the pointer members red , green and blue to the new instance. 这会将指针成员redgreenblue复制到新实例。 Then the old instance that you copied will be destroyed when it goes out of scope, causing the pointers to be deleted. 然后,您复制的旧实例超出范围时将被销毁,从而导致指针被删除。 The one you copied into the vector will then have invalid pointers since the target of the pointer is thus deleted. 复制到向量中的那个指针将具有无效的指针,因为这样删除了指针的目标。

A good rule of thumb is that if you have any raw pointer members, then you need to make a copy constructor and operator= that will handle this situation correctly, by making sure that the pointers are given new values and not shared, or that ownership is transferred between the instances. 一条好的经验法则是,如果您有任何原始指针成员,那么您需要制作一个复制构造函数和operator= ,以确保正确地处理了这种情况,方法是确保为指针赋予新的值并且不共享它们,或者确保所有权在实例之间传输。

For example, the std::auto_ptr class has a raw pointer - the semantics of the copy constructor is to transfer ownership of the pointer to the target. 例如, std::auto_ptr类具有原始指针-复制构造函数的语义是将指针的所有权转移到目标。

The boost::shared_ptr class has a raw pointer - the semantics is to share ownership by means of reference counting. boost::shared_ptr类具有原始指针-语义是通过引用计数来共享所有权。 This is a nice way to handle std::vectors containing pointers to your class - the shared pointers will control the ownership for you. 这是处理包含指向您的类的指针的std::vectors的好方法-共享的指针将为您控制所有权。

Another way might be to use vectors to take the place of your member pointers - the member pointers are simply aliases for your arrays anyway, so the vector is a good substitute. 另一种方法可能是使用向量代替成员指针-成员指针无论如何只是数组的别名,因此向量可以很好地替代。

Unless you have a deep copy constructor and assignment operator for the FrameData class my gut feeling is that the compiler generates a copy constructor to use with push_back. 除非您对FrameData类有一个深层的复制构造函数和赋值运算符,否则我的直觉是编译器将生成一个复制构造函数以与push_back一起使用。 Automatically generated copy constructors and assignment operators will do a memberwise copy, which will result in a shallow copy in this instance. 自动生成的副本构造函数和赋值运算符将进行成员复制,在这种情况下将导致浅表副本。 Unfortunately your destructor doesn't know about the copy so during the copying, there is a good chance that a temporary copy of FrameData gets destroyed and that will take all your data with it. 不幸的是,您的析构函数不了解该副本,因此在复制过程中,很有可能会销毁FrameData的临时副本,并且该副本将同时处理您的所有数据。

Calling the destructor again later in the process will result in a double free, plus other allocations might have used part of the "free" memory. 在此过程的稍后部分再次调用析构函数将导致双重释放,另外其他分配可能已经使用了部分“释放”内存。 That looks like a good reason for heap corruption from here. 这似乎是从此处破坏堆的一个很好的原因。

Best way to find problems like these is usually to use a tool like ValGrind or Purify to pinpoint the problem. 找到此类问题的最佳方法通常是使用ValGrind或Purify之类的工具来查明问题。

This is not an answer to your question , just an observation. 这不是您的问题的答案 ,只是一个观察。

Since your frame data could be large, to avoid excessive copying, may be it's better for you to use 由于帧数据可能很大,为避免过度复制,使用它可能会更好

std::vector<FrameData *> frames;

EDIT: As others have pointed out, this will also solve your crashing problem. 编辑:正如其他人指出的那样,这也将解决您的崩溃问题。

You are correct about push_back making a copy, but does FrameData have a suitable copy constructor and assignment operator? 您对push_back进行复制是正确的,但是FrameData是否具有合适的复制构造函数和赋值运算符?

Also, why the cast here: 另外,为什么要在这里进行演员:

delete[] ((uint8_t*) red[i]);

In C++, if you have to use a C-style (or reinterpret) cast, the code is almost certainly wrong. 在C ++中,如果必须使用C样式(或重新解释)强制转换,则代码几乎肯定是错误的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM