Школоло / Говнокод #7110 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
  84. 84
  85. 85
  86. 86
  87. 87
  88. 88
  89. 89
  90. 90
  91. 91
  92. 92
  93. 93
  94. 94
  95. 95
  96. 96
  97. 97
  98. 98
  99. 99
  100. 100
// к говнокоду 7101:

interface

type TObjectAuto = class;
TSmartPtr = packed record
  data: TObjectAuto;
end;
TSmartPtrA = array of TSmartPtr;
//-------------------------------------------------------------------------------------------
// класс с "авто"-деструктором
TObjectAuto = class(TObject)
  n: integer; // для тестов
  constructor Create(var ptr: TSmartPtrA);
  destructor Destroy(); override;
end;

implementation

uses Windows;

var winheap: Cardinal;
var savedlinks: array of integer; // в тестовом примере сойдет, а вообще надо хеш-таблицу
//-------------------------------------------------------------------------------------------
constructor TObjectAuto.Create(var ptr: TSmartPtrA);
begin
  inherited Create();
  SetLength(ptr, 1);
  ptr[0].data := self;
  // сохраняем адрес выделенной памяти под массив (у него еще есть длина и счетчик ссылок)
  SetLength(savedlinks, Length(savedlinks) + 1);
  savedlinks[Length(savedlinks) - 1] := integer(ptr) - 2 * sizeof(integer);
end;
//-------------------------------------------------------------------------------------------
destructor TObjectAuto.Destroy();
begin
  n := 0; // сюда брякпойнт поставим:)
  inherited;
end;
//-------------------------------------------------------------------------------------------
function WinGetMem(Size: Integer): Pointer;
begin
  Result := HeapAlloc(winheap, 0, Size);
end;
//-------------------------------------------------------------------------------------------
function WinFreeMem(P: Pointer): Integer;
var i, j: integer;
begin
  // ищем адрес освобождаемой памяти среди сохраненных
  i := 0; j := 0; while(i < Length(savedlinks))do begin
    // если нашли, то вызываем "авто"-деструктор
    if (savedlinks[i] = integer(P)) then 
      TSmartPtrA(integer(p) + 2 * sizeof(integer))[0].data.Free()
    else begin
      savedlinks[j] := savedlinks[i];
      inc(j);
    end;
    inc(i);
  end;
  SetLength(savedlinks, j);
  HeapFree(winheap, 0, P);
  Result := 0;
end;
//-------------------------------------------------------------------------------------------
function WinReallocMem(P: Pointer; Size: Integer): Pointer;
begin
  Result := HeapReAlloc(winheap, 0, P, Size);
end;
//-------------------------------------------------------------------------------------------
var winmem: TMemoryManager = (
            GetMem: WinGetMem;
            FreeMem: WinFreeMem;
            ReallocMem: WinReallocMem);
    oldmem: TMemoryManager;
//-------------------------------------------------------------------------------------------
initialization
begin
  winheap := GetProcessHeap();
  GetMemoryManager(oldmem);
  SetMemoryManager(winmem);
  SetLength(savedlinks, 0);
end;
//-------------------------------------------------------------------------------------------
finalization
begin
  SetLength(savedlinks, 0);
  SetMemoryManager(oldmem);
end;
//-------------------------------------------------------------------------------------------
end.

// пример использования:
procedure TfrmTest.Button1Click(Sender: TObject);
var ptr: TSmartPtrA;
    obj: TObjectAuto;
begin
  obj := TObjectAuto.Create(ptr);
  obj.n := 222; // ptr[0].data.n := 222;
  // тут obj удалится сам
end;

примерно так можно реализовать автодеструктор в delphi
для передачи в функцию нужно использовать ptr и работать с ним как ptr[0].data - неудобно конечно.
ЗЫ: код тестовый - в нем полно кривостей.

Запостил: ctm ctm, (Updated )

Комментарии (26) RSS

  • точнее к постам в говнокоде 7101 про автодеструктор 🙂
    Ответить
  • еще забыл написать: необходимо, чтобы модуль должен идти в проекте первым, т.к. в нем задается менеджер памяти
    Ответить
  • То есть реализована идея:
    1)При создании каждого 1 экземпляра класса - нужно создать 1 локальный массив.
    2)При создании каждого 1 класса - нужно создать 1 магический конструктор и 1 магический деструктор.
    3)Дописать ещё несколько костылей.
    3)Теперь объект соизволит удавлиться сам.
    4)??????
    5)PROFIT

    Умереть, не встать... Лучше я сам деструктор вызову, а потом уйду в другой язык и не вернусь.
    Ответить
  • Тут точно нет лишних костылей?
    1)Зачем winheap?
    2)Зачем SetLength(savedlinks, 0); в finalization?
    Ответить
    • 1. чтобы каждый раз не вызвать GetProcessHeap
      2. Ну так - для порядка. в нормальной реализации там должен быть класс хештаблицы или еще что может подойти, но не массив
      Ответить
  • Прочитал, врубился. Понравилось. Буду использовать, наверное.
    Претензии:
    Переопределять менеджер памяти через HeapAlloc не надо, это тормоза большие, лучше через старые GetMem/FreeMem. Стандартный менеджер сам по себе весьма хорош, надо только сделать над ним небольшую надстройку.
    Ну и мёртвая привязка начала блока к -8 му смещению указателя на динмассив не очень. Надо найти структуру из модуля System и привязаться к её размеру.
    Ответить
    • да тормоза большие, но утечек из-за кривого дельфового не будет.
      да, конечно лучше через структуру.
      в реальных проектах сам вряд ли буду использовать - проще самому освободить. ну или если кто-нибудь освободит вручную - то будет плохо.
      Ответить
      • > да тормоза большие, но утечек из-за кривого дельфового не будет.

        Что-то не замечал утечек из-за плохой работы именно менеджера памяти.
        Ответить
        • в Д7 проявляется точно:
          var n: array of Pointer;
          i: integer;
          p: Pointer;
          begin
          SetLength(n, 10000);
          for i := 0 to 9999 do begin
          GetMem(p, 100000); (**)
          GetMem(n[i], 1);
          FreeMem(p); (**)
          end;
          // Сюда ставить брякпойнт, смотреть, сколько сожрал, сравнить с вариантом без строк (**)
          // дальше честная очистка n.
          for i := 0 to 9999 do FreeMem(n[i]);
          SetLength(n, 0);
          Ответить
          • Это ничего не значит. Эту память он мог приберечь на будущие выделения.
            Ответить
            • >на будущие выделения.
              От дельфи и так много выделений. Говнопрограмма на говнопрограмме с его то порогом вхождения. Зачем ещё?
              Ответить
            • код родился из реального проекта, где характер работы с памятью был похож. начали искать где утечки и дошли до этого:(
              кстати, если в getmem указать 1 метр вместо 100к, то будет EOutOfMemory
              Ответить
  • Ещё идея из этой области.

    У меня есть универсальный контейнер для всего, основан на префиксном дереве. Понятно, что такм везде указатели, уничтожать его надо вручную. Так я всерьёз думал ради безопасности переписать это дерево на динмассив. То есть когда нужна новая вершина - мы удлиняет массив на 1 и пишем в эту вершину указатель на новый элемент индекс нового элемента. Надо убрать вершину - ну помечаем элементы массива как неиспользуемые, например. Потом перекидываем элементы, перекинув индекс родителя.
    Ответить
    • Блин, какие костыли и порча объектной абстракции и семантики на пустом месте (пустое место=дельфи?)...
      Ответить
    • вполне достаточно скрыть всю работу с указателями внутри контейнера.
      ну а сам контейнер придется создавать/удалять.при переходе на массивы скорее всего проиграете в производительности.
      стоит ли впадать в крайности?
      Ответить
      • Работу-то я внутрь скрыл, но вот напрягает "ну а сам контейнер придется создавать/удалять".
        Что касается производительности, то мне в таких вещах лишь бы алгоритмическая сложность не портилась.
        Ответить
        • ну попробуйте, заодно и опытом поделитесь:)
          Ответить
  • обычная реализация на интерфейсах будет работать и быстрее и для всех объектов, а не только наследников TObjectAuto , а для всех объектов.
    Ответить
    • Хелпером?
      Не взлетить. Компилер меджик мать ее
      Ответить
      • Я думал, намного больше коментов будет. Очень плохой ТараcВ, просто очень плохой ТараcВ!
        Ответить

Добавить комментарий

Где здесь C++, guest?!

    А не использовать ли нам bbcode?


    8