В этой статье я хочу показать, как можно оформить ручное управление памятью в C# и сделать затем с его помощью простой однонаправленный список.
Для затравки забежим немного вперёд и покажем, как в итоге будет создаваться экземплят такого списка:
new CustomLinkedList<double, ListBasedAllocator<CustomLinkedListNode<double, int>>, int>()
Сразу условимся, что мы не будем использовать unsafe контекст. Это снижает портируемость и нивелирует всё удовольствие, что можно получить при разработке заявленного списка.
Свои указатели
К счастью (!), .NET не поддерживает указатели в том виде, в котором их поддерживает C++. Всё, что доступно при разработке управляемого кода — это
Инстансы ссылочных типов. Все они хранятся в куче и обслуживаются сборщиком мусора. Поскольку мы пишем своё управление памяти, о них можно забыть сразу.
Завёрнутые в коробку инстансы типов-значений. В принципе, они мало отличаются от инстансов ссылочных типов и нам не подходят по тем же причинам.
Управляемые указатели. Могут указывать как в кучу, так и на стек. Насколько я знаю, они могут храниться только в локальных переменных и/или передаваться в другие функции при вызове. Поэтому они нам тоже не подойдут.
Решим мы эту проблему просто: не будем её решать вообще на данном этапе, а отложим до лучших времён. Пока же договоримся везде использовать параметр типа Pointer.
Модификация структур, содержащихся в контейнерах
В этой статье я буду рассматривать аллокаторы для структур данных фиксированного размера. Опишем интерфейс такого аллокатора:
/// <summary>
/// Обобщённый интерфейс для аллокаторов объектов определённого типа.
/// </summary>
/// <typeparam name="T">Тип объектов, с которыми работает аллокатор</typeparam>
/// <typeparam name="TPointer">Тип указателя, используемый для доступа к памяти</typeparam>
public interface ICustomTypeAllocator<T, TPointer>
{
/// <summary>
/// Выделяет область памяти для одного объекта и возвращает указатель на эту область
/// </summary>
TPointer Allocate();
/// <summary>
/// Освобождает память, по адресу pointer.
/// Если установлен флаг checkErrors, аллокатор по возможности производит проверку того,
/// что данный указатель действительно указывает на ранее выделенный блок памяти,
/// и, если это не так, генерирует исключение.
/// </summary>
/// <param name="pointer">Указатель на область памяти, подлежащую освобождению</param>
/// <param name="checkErrors"></param>
void Free(TPointer pointer, bool checkErrors = false);
/// <summary>
/// Позволяет осуществлять доступ к объекту по адресу pointer.
/// </summary>
/// <param name="pointer">Адрес области памяти, в которой находится объект.</param>
T this[TPointer pointer] { get; set; }
Read more: Habrahabr.ru
0 comments:
Post a Comment