Хакнуть динамический массив?

Обсуждаются как существующие проекты (перевод документации, информационная система и т.п.), так и создание новых.

Модератор: Модераторы

Хакнуть динамический массив?

Сообщение hinst » 15.03.2014 20:09:18

У меня вот какая идея: хакнуть как-нибудь динамический массив.
Известно, что динамический массив освободится автоматически когда последняя ссылка на него пропадёт из области видимости
А что если как-нибудь засунуть туда свой объект? И чтобы он тоже как-нибудь освобождался автоматически, ну я думаю понятно
Код: Выделить всё
var
  s: TStrings;
begin
  s := TStringList.Create;
  s.Free;
end;

Вот примерно как я хочу сделать:
Код: Выделить всё
var
  s: TDynStrings;
begin
  CreateDyn(s, TStringList.Create);
end;   // и здесь s освобождается автоматически

Тут главный фокус в том, чтобы к деструктору динамического массива приделать свой код
И это возможно, ведь если сделать динамический массив string'ов, то при разрушении массив освободит и массив указателей на string'и, то есть себя, и ещё освободит сами string'и. Остаётся только сделать, чтобы вместо деструктора (точнее, уменьшателя числа ссылок) string он вызвал деструктор объекта Free, и тогда мы получим автоматические массивы экземпляров классов, которые не надо освобождать, типа как в Java, ок да, только у нас (у меня?) принцип будет другой
Пока не придумал, как именно это лучше сделать, и следует ли это вообще сделать

Добавлено спустя 1 минуту 19 секунд:
Надо в общем найти, где компилятор хранит указатель на тот код, который должен вызваться при освобождении динамического массива

Добавлено спустя 20 секунд:
там typinfo, все дела
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Хакнуть динамический массив?

Сообщение скалогрыз » 16.03.2014 02:04:55

1) array of Interfaces; - освободит объекты (при условии что счётчик ссылок скинется в ноль)
2) TObjectList (параметр, FreeObjects ... или как-то так, который будет освобождать, объекты при их удалении и очищении самого листа)

пожалуйста, не издевайтесь над паскалем. Он (язык) этого не заслужил.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Хакнуть динамический массив?

Сообщение Mirage » 16.03.2014 16:08:02

Я так понимаю, что все это нужно, чтобы получить подобие сборщика мусора?
Есть метод проще - интерфейсная ссылка может вызывать деструктор объекта, на который она указывает, если реализовать соответствующим образом методы _addref/_release.
Это уже даже сделано, например тут:
https://github.com/casteng/base/blob/dev/Basics.pas
IRefcountedContainer/ TRefcountedContainer.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Хакнуть динамический массив?

Сообщение hinst » 17.03.2014 15:05:25

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

Добавлено спустя 2 минуты 6 секунд:
Это увеличит потребление памяти и торможение
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Хакнуть динамический массив?

Сообщение wavebvg » 17.03.2014 15:27:29

Попробуйте разделить данные и интерфейс работы с этими данными
Это помагает не считать того, что можно было бы не считать
Если же работаете со структурой (деревом) - то работайте с чилдами
Ну и в объектном паскале есть такое понятие как объект и ничего хакать не нужно будет http://wiki.freepascal.org/Programming_Using_Objects
wavebvg
постоялец
 
Сообщения: 354
Зарегистрирован: 28.02.2008 04:57:35

Re: Хакнуть динамический массив?

Сообщение скалогрыз » 17.03.2014 19:09:13

hinst писал(а):В интерфейсе ещё всякие дополнительные данные хранятся (особенно в COM-интерфейсе), а мне от него нужно только возможность подсчёта ссылок. Поэтому использовать интерфейсы для этой цели плохо.

Добавлено спустя 2 минуты 6 секунд:
Это увеличит потребление памяти и торможение

DirectX API полносью на COM Интерфейсах построено. ... тормозят игры на DirectX?

Можно ли какие-нить цифры получить по сравнению производительности?
array of TObject vs TFPObjectList vs array of Interface

Альтернативное решение - используй свой рефкаунтинг (для своих объектов). ООП-же!
Код: Выделить всё
TMyRefObject = class(TObject)
public
  procedure AddRef; // увеличивает кол-во ссылок
  procedure Release; // уменьшите кол-во ссылок - если ссылки сбросились в 0 - то освобождает объект
end;

TMyRefObjectArray = class(TObject)
  property Item[i: integer]: TMyRefObject read write; // увеличивае, уменьшает количество ссылок при присваиваниию
end;
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Хакнуть динамический массив?

Сообщение hinst » 17.03.2014 19:38:52

скалогрыз писал(а):Альтернативное решение - используй свой рефкаунтинг (для своих объектов). ООП-же!


но блин::: как сделать чтобы компилятор вызывал эти методы автоматически? при присвоении чтобы вызывал мой AddRef, а при выходе переменной из области видимости вызывал бы Release? вопрос весь по существу в этом
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Хакнуть динамический массив?

Сообщение скалогрыз » 17.03.2014 20:12:42

hinst писал(а):но блин::: как сделать чтобы компилятор вызывал эти методы автоматически? при присвоении чтобы вызывал мой AddRef, а при выходе переменной из области видимости вызывал бы Release? вопрос весь по существу в этом

Никак. Автоматизм есть, но только в Интерфейсах. - и к стати с этим связан потенциальный ряд ошибок (и разница в реализации между Delphi и FPC).

:oops: С такими требованиями, Паскаль, оказывается, уже язык низкого уровня (ибо заставляет делать своими руками) :oops: Понятие "низкий уровень" резко повысилось в последние годы :mrgreen: Спасибо Java, JavaScript, C#?, PHP. Не посвящённый человек разницу всё-равно не почуствует...

Опять же, уже говорил, но повторюсь - практика ручного вызова AddRef / Release есть в ObjC и в С++ и в С (в зависимости от библиотеки), и никого это не смущает. Вопрос дисциплины и привычки - не более.

Тут у меня возникает вопрос, а разве использование AddRef / Release в TObject не сравняется по скорости с AddRef / Release в интерфейсах ? :) и если да, то почему бы не использовать интерфейсы (раз уж в них и так всё автоматически) ? ;)
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Хакнуть динамический массив?

Сообщение hinst » 17.03.2014 20:18:39

В интерфейсах меня вот что смущает причём уже давно:
Имеется вот такой код в RTL:
Код: Выделить всё
function TInterfacedObject._Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};

  begin
     _Release:=interlockeddecrement(frefcount);
     if _Release=0 then
       self.destroy;
  end;

А что если
Код: Выделить всё
     
_Release:=interlockeddecrement(frefcount);
// вот в этом моменте произойдёт ещё один вызов interlockeddecrement(frefcount);?????
if _Release=0 then
  self.destroy;

Понятно что можно по-своему сделать, чтобы и decrement, и сравнение были в одной атомарной секции, просто не понятна логика разработчиков, который этот код писали
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Хакнуть динамический массив?

Сообщение скалогрыз » 17.03.2014 20:25:32

hinst писал(а):но блин::: как сделать чтобы компилятор вызывал эти методы автоматически? при присвоении чтобы вызывал мой AddRef, а при выходе переменной из области видимости вызывал бы Release? вопрос весь по существу в этом


Можно ещё клянчить у разработчиков Паскаля переопределяемую "операцию присваивания" (т.е. чтобы можно было переопределить ":=") ну и соответственно "операцию выходя из поля видимости" (операция обратная присваиванию).
тогда "автоматический" AddRef / Release можно будет реализовать.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Хакнуть динамический массив?

Сообщение Mirage » 17.03.2014 20:28:52

hinst писал(а):В интерфейсе ещё всякие дополнительные данные хранятся


Например?

hinst писал(а): (особенно в COM-интерфейсе),


О COM вообще речь не шла.

hinst писал(а): а мне от него нужно только возможность подсчёта ссылок. Поэтому использовать интерфейсы для этой цели плохо.
Это увеличит потребление памяти и торможение


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

hinst писал(а):А что если
Код: Выделить всё
     
_Release:=interlockeddecrement(frefcount);
// вот в этом моменте произойдёт ещё один вызов interlockeddecrement(frefcount);?????
if _Release=0 then
  self.destroy;


А ты проверь.

hinst писал(а):Понятно что можно по-своему сделать, чтобы и decrement, и сравнение были в одной атомарной секции, просто не понятна логика разработчиков, который этот код писали


Видимо, разработчики многопоточный код писать умеют и логика была, например, следующей: засовывать все в критическую секцию не фонтан, т.к. те еще тормоза будут.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Хакнуть динамический массив?

Сообщение Sergei I. Gorelkin » 17.03.2014 20:36:01

Что будет, что будет... Откуда вообще возьмется еще один вызов _Release, если речь идет о последней ссылке на интерфейс?
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1395
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Хакнуть динамический массив?

Сообщение скалогрыз » 17.03.2014 20:40:43

hinst писал(а):
Код: Выделить всё
     
_Release:=interlockeddecrement(frefcount);
// вот в этом моменте произойдёт ещё один вызов interlockeddecrement(frefcount);?????
if _Release=0 then
  self.destroy;

Понятно что можно по-своему сделать, чтобы и decrement, и сравнение были в одной атомарной секции, просто не понятна логика разработчиков, который этот код писали


Имеется в виду
"// вот в этом моменте произойдёт ещё один вызов interlockedincreament(frefcount);????? и при этом _Release уже 0 ?"
Потому что если произойдёт interlockeddecrement, то ошибка в где-то коде (Release не парный addRef)

За логикой очень возможно стояла Делфи совместимость, либо то что, полное освобождение объекта не обратимо.
Либо даже если взять проверку и сравнение атомарной операцией, делу не поможешь, т.к. если код уже ожидает на входе в _AddRef
Код: Выделить всё
function TInterfacedObject._Release : longint;
begin
  // thread 1 - уже ждёт секцию
   EnterCriticalSection;
   _addref:=interlockedincrement(frefcount);
   LeaveCriticalSection;
end;

function TInterfacedObject._Release : longint;
begin
   EnterCriticalSection;
  // thread 2 - вошёл и сейчас грохнет этот объект
  _Release:=interlockeddecrement(frefcount);
  if _Release=0 then self.destroy;
  LeaveCriticalSection;
end;

... то всё-равно упадёт обязательно.
скалогрыз
долгожитель
 
Сообщения: 1803
Зарегистрирован: 03.09.2008 02:36:48

Re: Хакнуть динамический массив?

Сообщение hinst » 18.03.2014 14:14:12

я рассуждал над вопросом, и пришёл к выводу, что если сделать проверку и сравнение атомарной операцией, то делу как раз таки поможешь, однако, при одном условии: если нет никаких "слабых" ссылок на объект, то есть, все, кто имеют ссылку на объект, её имеют. То есть, если количество ссылок доходит до нуля, то никто уже не может вызвать для данного объекта _AddRef, если только не было мест, которые ссылку имели, но _AddRef не делали, так что атомарность сравнения и уничтожения проблему решает, кроме, как я уже сказал, случаев, когда нужно, чтобы были так называемые слабые ссылки, которые есть, но _AddRef не делали

Что меня во всей этой системе подсчёта ссылок интересует, так это то, что если делать так, как я говорю, то есть, делать эту самую атомарность для двух операций, то функции interlockedincrement и interlockeddecrement тут уже не подойдут, и нужно будет на каждый объект создавать критическую секцию или мьютекс. Не уверен, отличаются ли эти два объекта на уровне операционной системы. Вот как бы так сделать, чтобы найти все объекты, которые используются только из одного потока, и для них не создавать критическую секцию, да и interlocked-функции для них можно не использовать, так как если объект используется только из одного потока, то вызовы никогда не пересекутся. А для всех объектов, которые могут использоваться из разных потоков, включить использование критических секций. Тут возможны принципиально несколько подходов:

1. Включить критические секции для всех ссылочноподсчётных классов, и позже просто стараться использовать их по минимуму, то есть, в местах, где это очень хочется, а все остальные классы по возможности оставить обычными, то есть, без подсчёта ссылок, чтобы критические секции в каждом объекте не замедляли работу программы

2. Контролировать тип ссылочноподсчётного объекта вручную: например, чтобы в конструкторе был аргумент threadSafe, если указываешь True, то критическая секция используется, иначе не используется. В этом подходе придётся много думать, так как придётся заранее догадаться, будет данный объект использоваться из нескольких потоков, или не будет.

3. Сделать какой-то статический анализатор кода, который будет догадываться по коду, какие ссылочноподсчётные объекты надо синхронизировать, а какие не надо, но это очень сложно сделать такой анализатор

4. Сделать, чтобы объект при каждом вызове AddRef запоминал CurrentThreadId, хранил предыдущий ThreadID, и каждый раз их сравнивал, и как только они впервые не совпадут, так сразу включал критическую секцию, но это дурацкий какой-то подход потому, что сложно сказать, будет ли он работать на 100 % или нет, или же придётся присваивание PreviousThreadId := CurrentThreadId и сравнение тоже синхронизировать, тогда будет ещё хуже, критических секций будет ещё больше

5. А что если сделать, чтобы на все экземпляры одного класса была одна критическая секция? Или вообще одна на всех. Тогда будет выигрыш по памяти, но проигрыш по производительности. Дурацкий подход. Но в принципе можно попробовать

В общем, всё надо пробовать и тестировать, в том числе и COM-интерфейсы
Кто-то тут написал, что COM-интерфейсы тут ни при чём, а я говорю, что причём. В том и дело, что в FPC два режима интерфейсов: CORBA и COM. А какого-то абстрактного "просто интерфейса" на уровне языка нет. Для интерфейсов CORBA подсчёт ссылок не делается. Остаются интерфейсы COM.

Добавлено спустя 1 минуту 54 секунды:
Вот по поводу интерфейсов: только что прочитал
Код: Выделить всё
  - COM, CORBA and raw interfaces support

здесь: http://sourceforge.net/projects/freepas ... n32/2.6.4/
Вот что они хотели этим сказать? не слышал ничего про "raw interfaces". Это какая-то новая фича щито ли?
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Хакнуть динамический массив?

Сообщение Mirage » 18.03.2014 17:44:38

hinst, ты какую-то конкретную проблему решаешь, или просто рассуждаешь о тяжелых буднях интерфейсных ссылок?
Если конкретную, то озвучь.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

След.

Вернуться в Разное

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 19

Рейтинг@Mail.ru