Ошибка HEAP Неверный адрес указан для RtlValidateHeap

У меня проблемы с памятью. Я использую структуру следующим образом:

Файл package.h

#pragma once
#include <cstdlib>

struct Package {
    char *data;
    long long int *packageNumber;
    long long int *allPackages;

    Package(const int sizeOfData);
    ~Package();
};

Пакет.cpp

#include "Package.h"

Package::Package(const int sizeOfData) {
    void *ptr = malloc(2 * sizeof(long long int) + sizeOfData * sizeof(char));
    packageNumber = (long long int*) ptr;
    allPackages = (long long int*) ((long long int*)ptr + sizeof(long long int));
    data = (char*)((char*)ptr + 2 * sizeof(long long int));
}

Package::~Package() {
    free(data);
    free(packageNumber);
    free(allPackages);
}

И в методе:

for (int j = 0; j < this->bufforSize || i * bufforSize + j < allPackages; j++) {
            Package package(this->packageSize);
            this->file->read(package.data, this->packageSize);
            *package.allPackages = allPackages;
            *package.packageNumber = i * this->bufforSize + j;
            this->dataPacked->push_back(package);
        }

после конца скобок выдает ошибку: "HEAP[zad2.exe]: Invalid address specified to RtlValidateHeap( 00000056FEFE0000, 00000056FEFF3B20 )" Я понятия не имею, что я делаю неправильно. Пожалуйста, помогите, Михаил.

РЕДАКТИРОВАТЬ: теперь он работает для первой итерации цикла. Помогает, что я изменил деструктор на это:

Package::~Package() {
    free(packageNumber);
}

Но теперь деструктор выполняется два раза для одного и того же объекта структуры во 2-й итерации цикла.


person PianistaMichal    schedule 09.11.2015    source источник
comment
Зачем помечать это как C, когда очевидно, что вы используете C++. И если это это C++, почему бы не использовать new [ ] и delete[ ] или просто контейнер, такой как std::vector?   -  person PaulMcKenzie    schedule 09.11.2015
comment
Почему ты звонишь free 3 раза? Выполняется только один вызов malloc.   -  person PaulMcKenzie    schedule 09.11.2015
comment
Потому что я должен сделать это в непрерывном фрагменте памяти. Вся структура должна быть в одном месте.   -  person PianistaMichal    schedule 09.11.2015
comment
В malloc нет никакой магии, в отличие от использования new char [ ] или std::vector<char>. Все они делают в основном одно и то же: выделяют непрерывный кусок памяти в байтах. Разница, по крайней мере, с malloc и std::vector<char> в том, что вам больше не нужно вручную управлять выделением и освобождением, из-за чего у вас сейчас ошибка.   -  person PaulMcKenzie    schedule 09.11.2015
comment
@PaulMcKenzie Спасибо, но я хочу выделить память в C-way. Например, для меня лучше выделить массив n-размера char + m-size int.   -  person PianistaMichal    schedule 09.11.2015
comment
но я хочу выделить память в C-способе И новая проблема, с которой вы столкнулись сейчас с деструктором, заключается в том, что вы делаете что-то C и пытаетесь смешать это с C++. Если вы собираетесь использовать std::vector для хранения своих объектов, то вам нужно решить, хотите ли вы использовать стандартные контейнеры для своих элементов данных или использовать необработанную память и придерживаться правила 3, что вы хотите, это последнее, но ваш класс не может реализовать правило 3.   -  person PaulMcKenzie    schedule 09.11.2015
comment
stackoverflow.com/questions/4172722/what- это-правило трех   -  person PaulMcKenzie    schedule 09.11.2015


Ответы (2)


Прочтите описание free:

Поведение не определено, если значение ptr не равно значению, возвращенному ранее функциями std::malloc(), std::calloc() или std::realloc().

Тогда взгляните на свой код, обратите внимание на комментарии, которые я добавил.

void *ptr = malloc(2 * sizeof(long long int) + sizeOfData * sizeof(char));
packageNumber = (long long int*) ptr; // you got this from malloc
allPackages = (long long int*) ((long long int*)ptr + sizeof(long long int)); // the value of this pointer is not equal to anything returned by malloc
data = (char*)((char*)ptr + 2 * sizeof(long long int)); // the value of this pointer is not equal to anything returned by malloc either

И, наконец, в деструкторе:

free(data); // was not allocated with malloc -> undefined behaviour
free(packageNumber); // was allocated with malloc -> OK
free(allPackages); // was not allocated with malloc -> undefined behaviour

Вы пытаетесь удалить указатели, которые не получили от malloc. Это приводит к неопределенному поведению. Ошибка возникает из-за неопределенного поведения. Поймите, что free(packageNumber) освобождает весь блок памяти, выделенный с помощью malloc. Это включает в себя память, указанную data и allPackages.

Существует простое практическое правило: вызывать free ровно один раз при каждом вызове malloc/calloc. То же самое относится к delete+new и delete[]+new[].

person eerorika    schedule 09.11.2015
comment
Это отличное объяснение. Помогает, но теперь с этим связана еще одна ошибка. Появляется после этого. Почему моя программа выполнила деструктор второй раз во второй итерации цикла? - person PianistaMichal; 09.11.2015
comment
@PianistaMichal Вы копируете объект в вектор. Готов поспорить, что вы забыли следовать правилу трех и не реализовали правильный конструктор копирования. - person eerorika; 09.11.2015
comment
Вектор делает копии вашего объекта. Так как ваша структура Package не может быть безопасно скопирована, поместив ее в вектор, все ошибки, связанные с копированием объектов Package, становятся видимыми. Если вы хотите хранить объекты Package в контейнере, таком как std::vector, вам необходимо убедиться, что его можно безопасно копировать, реализуя правило 3 (поскольку у вас есть члены, которые являются указателями на динамически выделяемую память). - person PaulMcKenzie; 09.11.2015

allPackages = (long long int*) ((long long int*)ptr + sizeof(long long int));

Когда вы используете указатель long long int (в нашем случае это ptr после приведения) и хотите увеличить размер sizeof (long long int) байтов, вам просто нужно сделать ptr++;

Но я предлагаю вам переписать свой код и использовать 3 malloc вместо одного.

person Brahim    schedule 09.11.2015
comment
Я предлагаю не писать никаких malloc звонков. Просто измените data на std::vector<char>, и вы получите те же результаты, и все это без управления памятью. - person PaulMcKenzie; 09.11.2015