2015-11-09 3 views
0

У меня проблемы с памятью. Я использую-структуру таким образом:Ошибка 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(); 
}; 

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); 
     } 

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

EDIT: теперь он работает для первой итерации цикла. Помогает, что я изменил деструктор к этому:

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

Но теперь деструктора выполняется два времени на одном объекте STRUCT в 2'nd итерации цикла.

+0

Зачем отмечать это как 'C', когда очевидно, что вы используете C++. И если это * есть * C++, почему бы не использовать 'new []' и 'delete []' или просто контейнер, такой как 'std :: vector'? – PaulMcKenzie

+0

Почему вы называете 'free' 3 раза? Существует только один вызов 'malloc'. – PaulMcKenzie

+0

Becouse Я должен сделать это в фрагменте непрерывной памяти. Целая структура должна быть в одном месте. – PianistaMichal

ответ

2

Читать description из free:

The behavior is undefined if the value of ptr does not equal a value returned earlier by std::malloc(), std::calloc(), or 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[].

+0

Это замечательное объяснение. Это помогает, но теперь есть еще одна ошибка. После этого он появляется. Почему моя программа выполняла второй раз деструктор во втором повторении цикла? – PianistaMichal

+0

@PianistaMichal. Вы копируете объект в вектор. Я был бы готов поспорить, что вы забыли следовать правилу три и не реализовали правильный конструктор копирования. – user2079303

+0

Вектор делает копии вашего объекта. Поскольку ваша структура 'Package' не может быть безопасно скопирована, поместив ее в вектор, все ошибки, связанные с копированием объектов« Package », становятся доступными. Если вы хотите хранить объекты «Package» в контейнере, такие как 'std :: vector', вам необходимо убедиться, что он безопасно скопирован, реализуя правило 3 (поскольку у вас есть члены, которые являются указателями на динамически выделенную память). – PaulMcKenzie

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

При использовании длинного длинного указателя Int (в нашем случае это PTR после того, как литой), и вы хотите продвинуться SizeOf (длинный длинный ИНТ) байтам, вам просто нужно сделать PTR ++;

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

+1

Предлагаю не писать никаких ' malloc'. Просто измените 'data' на' std :: vector ', и вы получите одинаковые результаты, без управления какой-либо памятью. – PaulMcKenzie