TN002: Стійкі даних формат об'єкта

Цієї записці описується MFC процедур, які підтримують стійких об'єктів C++ і формат даних об'єкта, коли він зберігається у файлі. Це відноситься тільки до класи з DECLARE_SERIAL і IMPLEMENT_SERIAL макросів.

Проблема

Впровадження MFC стійкі даних спирається на компактний двійковий формат для збереження даних для багатьох об'єктів в одному суміжні частини файлу. Це двійковий формат надає структуру для як дані зберігаються, але це об'єкта Serialize член функції, що забезпечує фактичні дані, збережені на об'єкт.

MFC вирішує структуризації за допомогою класу CArchive. CArchive об'єкт забезпечує контекст для наполегливість, що триває з часу Архів створюється, поки CArchive::Close член функція викликається, або явно програмістом, або неявно деструктор, коли вийшов сферу, що містять CArchive.

Цієї записці описується виконання членами CArchive ReadObject та WriteObject. ReadObject і WriteObject не називаються безпосередньо на замість цього використовується операторами клас конкретних Типозбережна вставки та вилучення автоматично генеруються DECLARE_SERIAL і IMPLEMENT_SERIAL макросів.

клас CMyObject: Громадська CObject
{
 nbsp;  DECLARE_SERIAL(CMyObject)
};

IMPLEMENT_SERIAL (CMyObj, CObject, 1)

/ / Приклад використання (АР є CArchive &)
CMyObject * pObj;
CArchive & ar;
Залишено << pObj;        / / називає АР.WriteObject(pObj)
Залишено >> pObj;        / / називає АР.ReadObject(RUNTIME_CLASS(CObj))

Цієї записці описується код-одна з місцевих громад, що розташована у вихідному файлі MFC ARCOBJ.CPP. Основні реалізації CArchive можна знайти в ARCCORE.CPP.

Збереження об'єктів в магазин (CArchive::WriteObject)

Функція-член CArchive::WriteObject пише заголовку даних, що використовується для відновлення об'єкта. Ці дані, що складається з двох частин: тип об'єкта та стану об'єкта. Ця функція-член відповідає також за підтримання ідентифікації об'єкта, що записуються, так що зберігається лише одну копію, незалежно від кількості посилання на цей об'єкт (в тому числі циклічне посилання).

Збереження, що (вставити) і відновлення (вилучення) об'єкти спирається на кілька "оголошені константи". Це значення, які зберігаються в двійковій системі і важливу інформацію до архіву (Примітка префікса "w" вказує 16-розрядних кількостях):

Тег Опис
wNullTag Використовується для NULL об'єкт покажчиків (0).
wNewClassTag Вказує на те, клас опис, випливає, що є новим для цього context—(-1) Архів.
wOldClassTag Вказує на те, клас об'єкта, який був прочитаний було видно в цьому контексті (0x8000).

Під час зберігання об'єктів, Архів веде на CMapPtrToPtr ( m_pStoreMap) який зіставлення з збережених об'єкта до 32-розрядної стійкі ідентифікатор (PID). Ідентифікаційного номера присвоюється унікальний кожен об'єкт і кожен ім'я унікального сорту, збережений у контексті архіву. Ці СВПІ є роздавали послідовно, починаючи з 1. Важливо відзначити, що ці СВПІ мають не значення виходить за рамки архіву і, зокрема, не слід плутати з номер запису або інших елементів ідентичності.

Починаючи з версії 4.0 MFC клас CArchive був розширений для підтримки дуже великих архівів. У попередніх версіях ідентифікаційного номера була 16-розрядних кількість, обмеження Архів об'єктів (32766) 0x7FFE. СВПІ в даний час 32-бітної, але вони написані як 16-біт, якщо вони не більше, ніж 0x7FFE. Великий СВПІ записуються як 0x7FFF, які слідують PID 32-розрядні. Цей метод зберігає зворотну сумісність файлів.

Коли запит зберегти об'єкт Архів (як правило, через глобальні вставки оператор), перевірити зробив для NULL CObject вказівником; Якщо вказівник NULL, на wNullTag вставляється в потоці Архів.

Якщо у нас є реальний об'єкт вказівника, який може бути серіалізованной (клас-це клас DECLARE_SERIAL ), ми потім перевірити m_pStoreMap , щоб побачити, якщо об'єкт був збережений вже. Якщо вона має, ми вставити номер PID 32-розрядних, пов'язаних з цього об'єкта.

Якщо об'єкт не було збережено раніше, є дві можливості, які ми повинні брати до уваги: як об'єкт, так і точний тип (тобто, клас) об'єкта новачок в цьому контексті Архів або об'єкт має точний тип, вже бачили. Щоб визначити, якщо тип було видно ми запит m_pStoreMap для об'єкта CRuntimeClass , який відповідає CRuntimeClass об'єкт, асоційованих з об'єктом, який ми збереження. Якщо ми бачили цей клас до, WriteObject вставляє тег, який є побітового OR'ing wOldClassTag та індексу. Якщо новачок в цьому контексті Архів CRuntimeClass , потім WriteObject призначає нового ідентифікаційного номера для цього класу та вставте його в Архів, передували wNewClassTag значення.

Дескриптор для цього класу потім вставляються в Архів, за допомогою CRuntimeClass функції члена магазин. CRuntimeClass::Store вставляє схеми кількість класу (див. нижче) і ASCII текстові ім'я класу. Зауважте, що використання ASCII текстові ім'я не гарантує неповторність Архів усіх програмах, таким чином, бажано тег файли даних для запобігання корупції. Після введення інформації, клас Архів розміщення об'єкта в m_pStoreMap і потім викликає Serialize член функції вставки даних класу до архіву. Розміщення об'єкта у m_pStoreMap перед викликом Serialize запобігає збереження до магазину декілька копій об'єкта.

При поверненні до початкового абонента (зазвичай корінь мережі об'єктів), важливо, щоб Закрити архіву. Якщо зробити інші операції CFile , CArchive член функція флеш бути під назвою. Нездатність зробити це призведе до пошкоджений Архів.

Примітка   Ця реалізація накладає жорсткий ліміт 0x3FFFFFFE індексів за Архів контексті. Ця кількість становить максимальну кількість унікальних об'єктів та класи, які можна зберігати в одному архіві, але примітки, що на одному диску файлу може мати необмежену кількість контекстах Архів.

Завантаження об'єктів зі сховища (CArchive::ReadObject)

Завантаження (вилучення) об'єктів використовується функція член CArchive::ReadObject і є Конверс WriteObject. Як з WriteObject, ReadObject не називається безпосередньо на код користувача; код користувача слід викликати Типозбережна видобутку оператор, який називає ReadObject з очікуваним CRuntimeClass. Це гарантує цілісність тип операції екстракт.

Оскільки WriteObject реалізації призначено збільшення СВПІ, починаючи з 1 (0 типовий як NULL об'єкт), реалізація ReadObject можна використовувати масив підтримувати Державний архів контексті. Коли ідентифікаційного номера читати в магазині, якщо номер PID більше поточних Верхня межа m_pLoadArray, потім ReadObject знає що новий об'єкт (або клас опис) відповідає.

Схеми чисел

Схеми номер, який призначається до класу, коли зустрічається класу IMPLEMENT_SERIAL , є "версія" клас виконання. Схеми, що відноситься до реалізації класу, не на кількість разів даного об'єкта було зроблено стійкі (зазвичай називають версія об'єкта).

Якщо ви маєте намір підтримувати кілька різних реалізацій одного класу з часом, збільшуючи схеми, як ви переглянути ваш об'єкт Serialize член функція реалізації дозволить вам писати код, який можна завантажити об'єктів, збережені у попередніх версіях на impleme&ntation.nbsp;

CArchive::ReadObject член функція буде кидати CArchiveException , коли вона виявляє схеми Номер у стійкі магазин, який відрізняється від схеми кількість пам'яті, опис клас. Це не легко відновити цей виняток.

Ви можете використовувати VERSIONABLE_SCHEMA або схеми версії тримати цей виняток від кинув. За допомогою VERSIONABLE_SCHEMA, ваш код може вжити відповідних заходів в її Serialize функцію перевірки повернутого значення з CArchive::GetObjectSchema.

Покликання сериализации безпосередньо

Є багато випадків, де накладні загальні об'єкта Архів схему WriteObject та ReadObject не є необхідним або бажаного. Це загальний випадок serializing дані в CDocument. У цьому випадку Serialize функції члена CDocument називається безпосередньо, не з екстракт або вставити операторів. Вміст документа, у свою чергу можуть використовувати більш Загальна схема Архів об'єктів.

Виклик Serialize безпосередньо має такі переваги та недоліки:

Serialize називається безпосередньо на ваш документ, тому не зазвичай можливо для підоб'єктів документа до архіву посилання на їх основного документа. Ці об'єкти слід приділяти вказівник їх документі-контейнері явно або для карта CDocument вказівник ідентифікаційного номера, щоб перед тим, як ці зворотні посилання архівуються потрібно використовувати функцію CArchive::MapObject.

Як зазначалося вище, ви повинні кодування інформації версія і класу про себе при дзвінках Serialize безпосередньо, дозволяючи змінювати формат пізніше, зберігаючи зворотної сумісності зі старих файлів. Функцію CArchive::SerializeClassRef можна назвати явно перед безпосередньо serializing об'єкта або перед викликом базового класу.

Технічні примітки за номером |nbsp; Технічні примітки за категоріями

Index