Проблемы с удалением 2D динамического массива в C ++ (который в конечном итоге сохраняется в векторе) - PullRequest
1 голос
/ 06 августа 2009

Итак, у меня есть этот двумерный динамический массив, содержимое которого я хочу освободить, когда закончу с ним. Однако я продолжаю сталкиваться с кучей коррупции после деструктора. Код работает нормально (конечно, с утечками памяти), если я закомментирую деструктор. (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. Да, я должен использовать векторы. Но мне не разрешено.

Дополнительная информация:

Оператор = и конструктор копирования не определены. Я думаю, это причина проблемы.

Ответы [ 4 ]

5 голосов
/ 06 августа 2009

Ваша проблема, как вы уже догадались, здесь:

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

Вектор создает копии элементов, которые вы вставляете. Что у вас есть для вашего конструктора копирования и / или operator= для вашего класса? Если вы ничего не определили, то версия по умолчанию, которую создает для вас компилятор, просто делает копии членов вашего класса. Это скопирует элементы указателя red, green и blue в новый экземпляр. Тогда старый скопированный вами экземпляр будет уничтожен, когда он выйдет из области видимости, и указатели будут удалены. Тогда тот, который вы скопировали в вектор, будет иметь недопустимые указатели, так как цель указателя, таким образом, будет удалена.

Хорошее практическое правило заключается в том, что если у вас есть необработанные члены-указатели, вам необходимо создать конструктор копирования и operator=, который будет корректно обрабатывать эту ситуацию, убедившись, что указатели получают новые значения и не используются совместно. или что право собственности передается между экземплярами.

Например, класс std::auto_ptr имеет необработанный указатель - семантика конструктора копирования заключается в передаче владения указателем цели.

Класс boost::shared_ptr имеет необработанный указатель - семантика состоит в том, чтобы делить владение с помощью подсчета ссылок. Это хороший способ обработать std::vectors, содержащий указатели для вашего класса - общие указатели будут контролировать владение вами.

Другим способом может быть использование векторов вместо указателей ваших членов - указатели на членов в любом случае просто являются псевдонимами для ваших массивов, поэтому вектор является хорошей заменой.

1 голос
/ 06 августа 2009

Это не ответ на ваш вопрос , просто наблюдение.

Поскольку данные вашего кадра могут быть большими, чтобы избежать чрезмерного копирования, возможно, вам лучше использовать

std::vector<FrameData *> frames;

EDIT: Как уже отмечали другие, это также решит вашу проблему сбоя.

1 голос
/ 06 августа 2009

Если у вас нет глубокого конструктора копирования и оператора присваивания для класса FrameData, я чувствую, что компилятор генерирует конструктор копирования для использования с push_back. Автоматически сгенерированные конструкторы копирования и операторы присваивания сделают копирование по элементам, что в этом случае приведет к поверхностному копированию. К сожалению, ваш деструктор не знает о копии, поэтому во время копирования есть большая вероятность, что временная копия FrameData будет уничтожена и заберет все ваши данные.

Повторный вызов деструктора в процессе приведет к двойному освобождению, плюс другие выделения могли бы использовать часть «свободной» памяти. Это выглядит как хорошая причина для кучи повреждения отсюда.

Лучший способ найти такие проблемы, как правило, использовать инструмент, такой как ValGrind или Purify, чтобы точно определить проблему.

0 голосов
/ 06 августа 2009

Вы правы в том, что push_back делает копию, но имеет ли FrameData подходящий конструктор копирования и оператор присваивания?

Кроме того, почему актерский состав здесь:

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

В C ++, если вам нужно использовать приведение в стиле C (или переинтерпретировать), код почти наверняка неверен.

...