Можете ли вы записать полиморфный класс на диск и выжить? - PullRequest
0 голосов
/ 30 июля 2010

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

Мой вопрос: могу ли я записать полиморфный класс на диск, а затем прочитать его позже и не получить неопределенное поведение?Я собираюсь догадаться не из-за vtables (я думаю они генерируются во время выполнения и уникальны для объекта?)

Т.е.

class A {
    virtual ~A() {}
    virtual void foo() = 0;
};

class B : public A {
    virtual ~B() {}
    virtual void foo() {}
};

A * a = new B;

fwrite( a, 1, sizeof( B ), fp );

delete a;

a = new B;

fread( a, 1, sizeof( B ), fp );

a->foo();

delete a;

Спасибо!

Ответы [ 3 ]

1 голос
/ 30 июля 2010

Я предлагаю вам взглянуть на Boost Serialization .

Мы используем термин «сериализация» для обозначения обратимой деконструкции произвольного набора данных C ++.структуры в последовательности байтов.Такая система может использоваться для восстановления эквивалентной структуры в другом программном контексте.В зависимости от контекста, это может быть использовано для сохранения объекта, удаленной передачи параметров или других средств.

0 голосов
/ 30 июля 2010

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

Каждый vtable сам генерируется во время компиляции и сохраняется где-то в результирующем исполняемом файле. То, что содержит каждый экземпляр объекта, является просто указателем на соответствующую vtable, и этот указатель не изменяется в течение времени жизни любого данного объекта. (Множественное наследование может быть немного сложнее, но для этого обсуждения эти детали не имеют значения. Указатели по-прежнему постоянны.)

Таким образом, если у объекта есть указатель vtable и вы записываете необработанные байты этого объекта на диск, то указатель vtable также записывается на диск. Если вы затем прочитаете эти байты во время одного и того же выполнения программы и вставите их в соответствующий объект, он может работать, поскольку виртуальная таблица будет по-прежнему находиться в том же месте и, следовательно, указатель виртуальной таблицы будет по-прежнему корректным .

(Однако обратите внимание, что все, что я только что объяснил, есть детали реализации. Хотя многие компиляторы обычно реализуют виртуальные функции таким образом, я не думаю, что какие-либо точные детали гарантированы стандартом C ++. Так что могут быть дополнительные потенциальные проблемы.)

Теперь, если это возможно, почему бы не хранить такие объекты в течение более длительного времени? Потому что у вас нет гарантии, что какая-то конкретная виртуальная таблица будет находиться в той же области памяти.

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

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

(И помимо vtables, что, если новые элементы данных должны быть добавлены к этим объектам в последующих версиях программы? Возможно, вам придется иметь дело со считыванием предыдущих версий байтов необработанных объектов в новые версии с новыми членами или другой состав членов. Это может быть сложным и уродливым, а также склонным к ошибкам.)


Теперь, даже если вы собираетесь временно хранить объекты для каждого выполнения программы. Я все еще не думаю, что это хорошая идея. Вы сильно ограничены в том, какие переменные могут содержать эти объекты. Нет смарт-объектов (std :: string, std :: vector и т. Д.). Нет указателей на память, выделенную для каждого объекта. Поэтому любые строки должны храниться в необработанных символьных массивах. Другое динамическое распределение должно быть превращено в фиксированные элементы или массивы элементов. Это означает, что вы теряете много преимуществ C ++ везде, где используются эти объекты.

Кроме того, эти объекты и схема записи их непосредственно на диск должны сопровождаться комментариями и документацией, предупреждающими обо всех опасностях, которые я описал. В противном случае, какой-то будущий программист может неосознанно принять решение добавить неправильный тип элемента данных Или, что еще хуже, они могут решить хранить такие объекты дольше, чем при выполнении программы, открывая их для серьезных сбоев и сбоев, которые могут произойти только в будущем (и, вероятно, в самый неподходящий момент).


В конце я настоятельно рекомендую использовать схему, которая хранит данные в формате, специально предназначенном для файла. Как уже упоминалось, Boost Serialization является хорошим вариантом. Если нет, то могут быть другие используемые библиотеки сериализации. Или же, в зависимости от ваших потребностей, вы можете без особых проблем запустить собственный механизм.

0 голосов
/ 30 июля 2010

Проблема не в vtable.Он хранится для каждого типа класса, а не для каждого экземпляра, поэтому вы не будете записывать его в файл.В основном ваш код должен работать (не пробовал).

Однако следует помнить, что чтение указателей / дескрипторов из файла не работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...