Можно ли написать действительно общую реализацию B + Tree, запеченную на диске? - PullRequest
1 голос
/ 26 ноября 2010

Я написал общую реализацию B + Tree в памяти на C ++ несколько раз назад, и я думаю о том, чтобы сделать ее постоянной на диске (именно поэтому B + Tree изначально была разработана).Моей первой мыслью было использовать mmap (я под Linux), чтобы иметь возможность манипулировать файлом как обычной памятью и просто переписать оператор new моих классов узлов, чтобы он возвращал указатели в отображенной части исоздать умный указатель, который может преобразовывать адреса ОЗУ в смещение файла, чтобы связать мои узлы с другими.Но я хочу, чтобы моя реализация была универсальной, чтобы пользователь мог хранить int, std :: string или любой другой пользовательский класс, который он хочет, в дереве B +.Вот где возникает проблема: для примитивных типов или агрегированных типов, которые не содержат указателей, это все хорошо, но как только объект содержит указатель / ссылку на выделенный объект кучи, этот подход больше не работает.

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

Ответы [ 3 ]

4 голосов
/ 26 ноября 2010

Насколько я знаю, есть три (несколько) простых способа решить эту проблему.

Подход 1 : написать std::streambuf, который указывает на некоторую предварительно выделенную память.

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

  • Pro: повторно использовать загрузки существующего кода.
  • Con: нет контроля над тем, как operator<< выплевывает содержимое.
  • Con: только текстовые представления.

Подход 2 : написать свою собственную (многократно перегруженную) выходную функцию.

  • Pro: может придумать двоичное представление.
  • Pro: точный контроль над каждым отдельным форматом вывода.
  • Con: переписать так много выходных функций ... написание перегрузок для новых типов клиентами является проблемой, потому что они не должны писать функции, попадающие в пространство имен вашей библиотеки ... если вы не прибегаете к Koenig (зависит от аргумента)lookup!

Подход 3 : wri* шаблон btree_traits<>.

  • Pro: может иметь двоичное представление.
  • Pro: точный контроль над каждым форматом вывода.
  • Pro: большеконтроль над выводом и форматом, что функция может содержать метаданные и все.
  • Con: все еще требует, чтобы вы / пользователи вашей библиотеки написали множество пользовательских перегрузок.
  • Pro: есть btree_traits<> не использовать operator<<, если кто-то не отменяет черты?
0 голосов
/ 26 ноября 2010

Обработка указателей и ссылок в общем виде означает, что вам необходимо проверить тип структуры, которую вы пытаетесь сохранить, и ее поля.C ++ - это язык, не известный своей рефлексивностью.

Но даже в языке с мощным рефлексией общее решение этой проблемы затруднено.Возможно, вы сможете заставить его работать для подмножества типов в языках более высокого уровня, таких как Python, Ruby и т. Д. Связанной и более мощной парадигмой является постоянный язык программирования .

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

0 голосов
/ 26 ноября 2010

Вы не можете написать действительно общую и прозрачную версию, поскольку, если указатель в нетривиальном элементе был выделен с помощью malloc (или new и new []), то он уже находится в куче.

A nonПрозрачное растворение может быть сериализацией класса, и это может быть сделано относительно легко.Перед сохранением класса вам нужно вызвать функцию сериализации, а перед извлечением этого класса вы должны вызвать десериализацию.Boost обладает хорошими функциями сериализации, которые вы можете использовать в своем B + Tree.

...