я рассуждаю о тяжёлых буднях самого себя, когда у меня некоторые объекты используются сразу во многих местах, и я не хочу думать, как их лучше освободить, я хочу, чтобы они освободились, как только последний указатель на них вышел из области видимости
Добавлено спустя 3 минуты 20 секунд:
Либо чтобы было "всё само", но это слишком как-то сложно реализовать
Либо чтобы я вызывал AddRef & Release сам, ведь Create и Free я и так уже вызываю, так что увеличение сложности тут будет не большое (хотя некоторое всё же будет)
Добавлено спустя 3 минуты 49 секунд:
Я думаю, что Хакнуть динамический массив - это как раз один из возможных подходов сделать всё само, вот я и думаю, в том числе, как бы это сделать
Добавлено спустя 5 минут 2 секунды:
Надо только присобачить туда свой деструктор
Добавлено спустя 14 секунд:
ну или не знаю, как это сработает на практике
Хакнуть динамический массив?
Модератор: Модераторы
hinst писал(а):Я думаю, что Хакнуть динамический массив - это как раз один из возможных подходов сделать всё само, вот я и думаю, в том числе, как бы это сделать
переписать компилятор, очевидно
Если ты ищешь "решения", то нужно думать, что "хак" не является "решением". Т.к. "хак" - обход правил, костыли, затычки. Надеюсь, намёк ясен
С освобождением динамических массивов/строк, при использовании потоков, всё не так очевидно, и не так гладко. Ибо операции переопредления не являются потоко безопасными. Т.е. расчитывать на автоматизм здесь - только себе вредить.
Вызывай явно AddRef / Release и не ошибёшься никогда, потому что твой код - что хочешь, то и делаешь.
Создал вариант модуля для того, чтобы прикрутить подсчёт ссылок к любому классу, не меняя сам класс:
Вроде бы, не плохо работает.
Что я заметил: с TRTLCriticalSection работает примерно в 2 раза быстрее, чем с TCriticalSection
Контейнер "приматывается" к существующему классу такой конструкцией:
Далее доступ к нему через поле V:
Принцип работы такой, что эти контейнеры можно присваивать: Count это Pointer, TRTLCriticalSection по сути тоже, V - тоже, поэтому если присваиванием создать множество копий shared-объекта, у них у всех будут указатели на одну и ту же критическую секцию, один и тот же объект, один и тот же Count
Увеличение и уменьшение счётчика методами Take, Drop.
Копирование:
Для наглядности можно будет сделать метод TakeCopy:
Код: Выделить всё
unit PSHO_GSharedU;
{$Mode ObjFPC}
{$LongStrings ON}
interface
uses
Classes, sysutils;
type
{ TGSharedObjectBase }
TGSharedObjectBase = object
protected
FValue: TObject;
public
property V: TObject read FValue write FValue;
protected
FLocker: TRTLCriticalSection;
public
property Locker: TRTLCriticalSection read FLocker write FLocker;
protected
FCount: PInteger;
protected
property Count: PInteger read FCount write FCount;
public
procedure Init(a: TObject);
public
procedure Take;
public
procedure Drop;
public
procedure Release;
public
procedure Take(a: TGSharedObjectBase);
end;
{ TGSharedObject }
generic TGSharedObject<T> = object(TGSharedObjectBase)
public
procedure Init(a: TObject);
protected
function GetValue: T;
protected
procedure SetValue(a: T);
public
property V: T read GetValue write SetValue;
end;
var
DebugOutputEnabled: Boolean;
implementation
{ TGSharedObjectBase }
procedure TGSharedObjectBase.Init(a: TObject);
begin
V := a;
if V <> nil then
begin
InitCriticalSection(FLocker);
Count := New(PInteger);
Count^ := 0;
end;
end;
procedure TGSharedObjectBase.Take;
begin
EnterCriticalsection(FLocker);
Inc(Count^);
LeaveCriticalsection(FLocker);
end;
procedure TGSharedObjectBase.Drop;
var
shouldRelease: Boolean;
begin
if V <> nil then
begin
EnterCriticalsection(FLocker);
Dec(Count^);
shouldRelease := Count^ <= 0;
LeaveCriticalsection(FLocker);
if shouldRelease then
Release;
end;
end;
procedure TGSharedObjectBase.Release;
begin
V.Free;
V := nil;
DoneCriticalsection(FLocker);
Dispose(Count);
end;
procedure TGSharedObjectBase.Take(a: TGSharedObjectBase);
begin
Drop;
V := a.V;
Locker := a.Locker;
Count := a.Count;
Take;
end;
{ TGSharedObject }
function TGSharedObject.GetValue: T;
begin
result := T(FValue);
end;
procedure TGSharedObject.SetValue(a: T);
begin
FValue := a;
end;
procedure TGSharedObject.Init(a: TObject);
begin
inherited Init(a);
end;
end.
Код: Выделить всё
unit PSHO_SharedClassesU;
{$Mode ObjFPC}
{$LongStrings ON}
interface
uses
Classes, PSHO_GSharedU;
type
TSharedStrings = specialize TGSharedObject<TStrings>;
implementation
end.
Код: Выделить всё
program TestGShared;
{$Mode ObjFPC}
{$LongStrings ON}
uses
sysutils,
dateutils,
Classes,
PSHO_GSharedU, PSHO_SharedClassesU;
const
ObjectCount = 1000000;
var
x: array of TSharedStrings;
m: TSharedStrings;
time: TDateTime;
i: Integer;
begin
time := Now;
SetLength(x, ObjectCount);
for i := 0 to ObjectCount - 1 do
begin
x[i].Init(TStringList.Create);
x[i].Take;
m.Init(nil);
m.Take(x[i]);
m.Drop;
end;
for i := 0 to ObjectCount - 1 do
begin
x[i].Drop;
end;
WriteLN(MilliSecondsBetween(Now, time));
end.
Вроде бы, не плохо работает.
Что я заметил: с TRTLCriticalSection работает примерно в 2 раза быстрее, чем с TCriticalSection
Контейнер "приматывается" к существующему классу такой конструкцией:
Код: Выделить всё
TSharedStrings = specialize TGSharedObject<TStrings>;Далее доступ к нему через поле V:
Код: Выделить всё
sharedStrings.V.Add('Meow');Принцип работы такой, что эти контейнеры можно присваивать: Count это Pointer, TRTLCriticalSection по сути тоже, V - тоже, поэтому если присваиванием создать множество копий shared-объекта, у них у всех будут указатели на одну и ту же критическую секцию, один и тот же объект, один и тот же Count
Увеличение и уменьшение счётчика методами Take, Drop.
Копирование:
Код: Выделить всё
x2 := x1;
x2.Take;
Для наглядности можно будет сделать метод TakeCopy:
Код: Выделить всё
x2 := x1.TakeCopy;
-
Mirage
- энтузиаст
- Сообщения: 881
- Зарегистрирован: 06.05.2005 20:29:07
- Откуда: Russia
- Контактная информация:
hinst писал(а):я рассуждаю о тяжёлых буднях самого себя, когда у меня некоторые объекты используются сразу во многих местах, и я не хочу думать, как их лучше освободить, я хочу, чтобы они освободились, как только последний указатель на них вышел из области видимости
А если два объекта друг на друга ссылаются?
Объекты, в рамках рассматриваемой задачи, можно поделить на две категории:
1. Временные и короткоживущие в рамках определенной области (например, процедуры). Их много, некоторые требуют правильной финализации и т.п. Действительно много мороки. Для них решение в топике есть.
2. Долгоиграющие. Часто непосредственно связаны с предметной областью и все такое. Вот жизненный цикл таких объектов отдавать на откуп автоматике, да еще такой несовершенной как подсчет ссылок, я бы не стал. Жизненный цикл таких объектов должен контролироваться осмысленно и централизованно, в соответствии с этой самой предметной областью. Пример - хотя бы VCL.
Наличие большого количества объектов, не попадающих ни в одну из категорий, т.е. по сути временных и при этом гуляющих где вздумается, вероятно сигнализирует о плохой архитектуре. В многопоточной среде они очень быстро приведут приложение к непотребному состоянию.
нет в жизни совершенства в общем
