C ++ - скрытие параметров шаблона от клиентского кода

0

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

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

Мое решение состояло в том, чтобы использовать частичную специализацию шаблонов, чтобы тип дескриптора был разработан во время компиляции, устраняя накладные расходы времени выполнения виртуальных машин и позволяя компилятору выполнять другие оптимизации (например: inlining)

/////////////////////////////////////////////////
/// \brief The basic handle class, acts as simple pointer
/// Single layer of indirection
/////////////////////////////////////////////////
template <typename T>
class Handle{
public:
    T* operator->(){return obj;}
    //other methods...
private:
    T* obj;
};

/////////////////////////////////////////////////
/// \brief Pointer specialization of the handle class, acts as a pointer to pointer
/// allowing allocators to rearrange their data
/////////////////////////////////////////////////
template <typename T>
class Handle<T *>{
public:
    T* operator->(){return *obj;};
    //other methods...
private:
    T** obj;
};

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

Эта проблема только ухудшается по мере добавления большего количества типов дескрипторов, или функция принимает более одного дескриптора, и все комбинации типов дескрипторов должны быть перегружены.

Либо мне нужно, чтобы все дескрипторы, указывающие на экземпляр "TypeA", имели тип Handle<TypeA> а затем использовали другой метод для специализирования шаблонов для предоставления различных функций или как-то скрыть параметр шаблона из любого кода, используя ручками. Как это можно достичь?

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

  • 0
    Модель распределителя C ++ никогда не была завершена и теперь бесполезна в качестве модели памяти. Используется только для разных стратегий выделения памяти. Но на самом деле ручка не работает. :( извиняюсь.
  • 0
    ru.wikipedia.org/wiki/Allocator_(C%2B%2B) "... изначально предназначенные распределители для полной инкапсуляции модели памяти, комитет по стандартам понял, что такой подход приведет к неприемлемому снижению эффективности. Чтобы исправить это, добавьте дополнительную формулировку был добавлен в требования к распределителю. В частности, реализации контейнеров могут предполагать, что определения типов распределителя для указателей и связанных целочисленных типов эквивалентны тем, которые предоставляются распределителем по умолчанию, и ... фактически противоречат первоначальным целям разработки для распределителей ... "
Показать ещё 1 комментарий
Теги:
pointers
templates
memory-management

1 ответ

3
Лучший ответ

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

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню