приведение из двоичного к многомерному массиву в куче

В настоящее время я использую двоичные файлы для быстрого доступа к пользовательским объектам, хранящимся в многомерных массивах, которые сохраняются в файл как массивы объектов. до сих пор чтение из файла не было слишком большой проблемой, так как я читал массив в идентичный массив объектов в стеке. это выглядит примерно так:

Foo foo[5][10];
ifstream infile("foofile.dat",ios::in|ios::binary);
infile.read((char*)&foo, sizeof Foo);

проблема, с которой я сейчас сталкиваюсь, заключается в том, что я все чаще храню большие объемы данных и переполняю свой стек при создании массива локальных объектов. тогда решение, казалось бы, создает локальный массив объектов в куче, и я не уверен, как его отформатировать, чтобы я мог привести его непосредственно из char *. вот как я бы выделил в куче:

Foo (*foo)[1000] = new Foo [500][1000];

однако это не кажется правильным форматом, если я хочу передать весь массив. например, если я попытаюсь сделать следующее, это не сработает:

ifstream infile("foofile.dat",ios::in|ios::binary);
infile.read((char*)(*foo), (sizeof Foo * 500 * 1000));  //or below
infile.read((char*)(&foo), (sizeof Foo * 500 * 1000));  //or below
infile.read((char*)(foo), (sizeof Foo * 500 * 1000));   //or below

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

Большое спасибо, Джим


person jim    schedule 08.07.2010    source источник


Ответы (3)


На мой взгляд, здесь нет особого смысла использовать механизмы C++ для выделения/освобождения, поскольку вы полностью перезаписываете данные своими чтениями. Так что не делайте new / delete вещей. Ваш актерский состав (char*) на самом деле является reinterpret_cast< char* >. Почему бы просто не использовать malloc правильного размера?

typedef Foo largeFoo[500][1000];
largeFoo* data = reinterpret_cast< largeFoo* >(malloc(sizeof largeFoo));

Затем прочитайте это (опять же с reinterpret_cast). Для удобства вы можете указать псевдоним своего указателя на ссылку.

largeFoo& foo = *data;

поэтому весь ваш оставшийся код может остаться таким же, как в версии стека, только с free вашего указателя в конце.

person Jens Gustedt    schedule 08.07.2010

Я не думаю, что используемое вами решение будет работать в общем случае; современные операционные системы используют рандомизацию кучи, поэтому не всегда возможно претендовать на одно и то же виртуальное адресное пространство при нескольких запусках программы.

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

Вы пытались сериализовать свои объекты в надлежащий формат на диске вместо того, чтобы просто писать двоичный двоичный объект?

person Borealid    schedule 08.07.2010
comment
ни один из моих сохраненных объектов не содержит указателей. это просто простые структуры на основе значений в многомерных массивах. т. е. объект представляет собой структуру с несколькими целыми числами и числами с плавающей запятой, размещенными в двумерном массиве. - person jim; 08.07.2010
comment
Тем не менее, изменение порядка байтов испортило бы целые числа ... Я просто не фанат двоичных дампов. Чтобы создать массив кучи, если вам необходимо, ваш новый вызов выше должен работать в сочетании с третьей строкой чтения, которую вы даете (приведение foo к char*). Я не вижу в этом ничего плохого. - person Borealid; 08.07.2010
comment
Кроме того, остерегайтесь выравнивания; если вы загрузите по неправильно выровненному адресу, ваши целые числа не будут работать. - person Borealid; 08.07.2010
comment
ха, знаете что, третья версия работает! я только пытался проверить значения с помощью отладчика Visual Studio, но он неправильно показывает значения кучи в массиве. присвоение одного из значений локальной переменной подтвердило, что данные были там. спасибо! - person jim; 08.07.2010
comment
правильно, да, у меня стандартный формат, который не меняется. поэтому я могу без особых проблем справляться с проблемами выравнивания порядка байтов, но точка зрения принята. еще раз спасибо. - person jim; 08.07.2010

Я так давно не писал неуправляемый код, что сейчас даже не могу вспомнить синтаксис. Был способ выделить непрерывный блок памяти и иметь возможность приведения к многомерному массиву. Если вы выделяете все, что вам нужно, за один раз, то сделайте так, чтобы каждый элемент указывал на соответствующее место в этом блоке. (Извинения за неправильный синтаксис/код).

void* ptr = malloc (void*)(sizeof(Foo) * 500 * 1000);
Foo** foo = (Foo**)ptr;
for (int i=0;i<500;i++) {
    foo[i] = (Foo*)(ptr+500*i*sizeof(Foo))
}
person Mark H    schedule 08.07.2010