Как загрузить / сохранить экземпляр класса C ++ (используя контейнеры STL) на диск - PullRequest
6 голосов
/ 26 апреля 2010

У меня есть класс C ++, представляющий иерархически организованное дерево данных, которое очень большое (~ Gb, в основном настолько большое, насколько я могу избежать в памяти) Он использует список STL для хранения информации на каждом узле плюс итераторы для других узлов. Каждый узел имеет только одного родителя, но 0-10 детей. Абстрагировано, это выглядит примерно так:

struct node {
public:
    node_list_iterator parent;              // iterator to a single parent node
    double node_data_array[X];
    map<int,node_list_iterator> children;   // iterators to child nodes
};

class strategy {
private:
    list<node> tree;        // hierarchically linked list of nodes
    struct some_other_data;
public:
    void build();           // build the tree
    void save();            // save the tree from disk
    void load();            // load the tree from disk
    void use();             // use the tree
};

Я хотел бы реализовать load () и save () на диск, и это должно быть довольно быстро, однако очевидные проблемы:

  1. Размер заранее не знаю;

  2. Данные содержат итераторы, которые являются летучими;

  3. Мое неведение C ++ невероятно.

Может кто-нибудь предложить чистое решение C ++, пожалуйста?

Ответы [ 6 ]

1 голос
/ 26 апреля 2010

На самом деле, я думаю, что ваш лучший вариант - переместить всю структуру данных в таблицы базы данных. Таким образом, вы получаете выгоду от людей намного умнее, чем вы (или я), которые занимаются вопросами сериализации. Это также избавит вас от необходимости беспокоиться о том, может ли структура вписаться в память.

1 голос
/ 26 апреля 2010

Повышенная сериализация уже предложена, и это, безусловно, разумная возможность.

Многое зависит от того, как вы собираетесь использовать данные - тот факт, что вы используете многостраничное дерево в памяти, не означает, что вам обязательно нужно хранить его как многострочное дерево на диске. Поскольку вы (очевидно) уже расширяете границы того, что вы можете хранить в памяти, очевидный вопрос заключается в том, заинтересованы ли вы просто в сериализации данных, чтобы вы могли при необходимости воссоздать то же самое дерево или хотите ли вы что-то вроде базы данных, чтобы вы могли загружать части информации в память по мере необходимости и обновлять записи по мере необходимости.

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

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

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

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

1 голос
/ 26 апреля 2010

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

File = Meta-data Node
Node = Node-data ChildCount NodeList
NodeList = sequence (int, Node)

То есть, когда сериализованный корневой узел содержит все узлы, либо прямые (дочерние), либо косвенные (другие потомки),Запись формата довольно проста: просто установите рекурсивную функцию записи, начиная с корневого узла.

Чтение не намного сложнее.std::list<node> итераторы стабильны.После того, как вы вставили корневой узел, его итератор не изменится, даже при вставке его дочерних узлов.Следовательно, когда вы читаете каждый узел, вы уже можете установить родительский итератор.Это, конечно, оставляет вас с дочерними итераторами, но они тривиальны: каждый узел является дочерним по отношению к своим родителям.Итак, после прочтения всех узлов вы исправите дочерние итераторы.Начните со второго узла, первого дочернего (первый узел был корневым) и перейдите к последнему дочернему элементу.Затем для каждого дочернего элемента C получите его родителя и дочерний элемент в коллекцию своих родителей.Теперь это означает, что вы должны отложить int дочерние идентификаторы во время чтения, но вы можете сделать это простым std :: vector, параллельным std::list<node>.После того, как вы исправили все дочерние идентификаторы у соответствующих родителей, вы можете отбросить вектор.

1 голос
/ 26 апреля 2010

boost.serialization - это решение, или ИМХО, вы можете использовать шаблон SQLite + Visitor для загрузки и сохранения этих узлов, но это будет не так просто, как кажется.

1 голос
/ 26 апреля 2010

Вы можете использовать библиотеку boost.serialization. Это сохранит все состояние вашего контейнера, даже итераторы.

0 голосов
/ 26 апреля 2010

Я уже что-то отвечал на SO, поэтому подведу итог:
1. Использовать базу данных.
2. Заменить смещения файлов ссылками (указателями).
3. Сохраняйте данные без древовидной структуры в записях , поскольку база данных будет .
4. Используйте XML для создания древовидной структуры, используя имена узлов вместо ссылок.
5. Это было бы намного проще, если бы вы использовали базу данных, такую ​​как SqLite или MySQL .

Когда вы тратите слишком много времени на «сериализацию» и меньше на основную цель вашего проекта, вам необходимо использовать базу данных .

...