Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Потрепаться";
Текущий архив: 2004.05.16;
Скачать: [xml.tar.bz2];

Вниз

Был, сегодня, на собеседовании   Найти похожие ветки 

 
Locker   (2004-04-23 14:42) [40]

unit Unit2;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs;

type
 TForm2 = class(TForm)
   procedure FormClose(Sender: TObject; var Action: TCloseAction);
 private
   pForm: pointer;
 public
   constructor Create(a_Owner: TComponent); override;
   destructor Destroy; override;
 end;

implementation

{$R *.dfm}

{ TForm2 }

constructor TForm2.Create(a_Owner: TComponent);
const
 bForm: TForm2 = nil;
begin
 if (bForm <> nil) then
 begin
   Self := bForm;
   Self.BringToFront; // это чтобы нагляднее было
 end
 else
 begin
   inherited Create(a_Owner);
   pForm := @bForm;
   TForm2(pForm^) := Self;
 end;
end;

destructor TForm2.Destroy;
begin
 TForm2(pForm^) := nil;
 inherited;
end;

procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 Action := caFree;
end;


 
Тимохов ©   (2004-04-23 14:45) [41]


> Locker   (23.04.04 14:42) [40]

на момент вызова create newinstance уже отработал, т.е. память взята.

скажу честно не проверял работает ли ваш код, но если даже и работает, то утечка памяти будет прикаждом вызове конструктора.


 
Locker   (2004-04-23 14:53) [42]

Небольшие уточнения:

В конструкторе:
if (bForm <> nil) then
begin
  Self.Free;
  Self := bForm;
  Self.BringToFront; // это чтобы нагляднее было
end


В деструкторе:
 if (pForm <> nil) then TForm2(pForm^) := nil;


 
Игорь Шевченко ©   (2004-04-23 14:56) [43]


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


Конечно, будет лажа. Поэтому содержательные деструкторы для таких объектов, например, освобождающие какие-то ресурсы, делать не надо. Я не говорил, что предлагаю универсальное решение.


 
Sha ©   (2004-04-23 14:58) [44]

> Тимохов ©   (23.04.04 14:38) [39]
>...добавить содержательный деструктор

Верно, но:

У Singleton класса не должно быть ни содержательного деструктора, ни содержательного конструктора.
Вся необходимая ининициализация и финализация делается
внутри NewInstance и FreeInstance.
По тем же причинам у него не должно быть наследников
при живом предке.


 
Locker   (2004-04-23 15:00) [45]

> работает ли ваш код

Как ни странно, работает. Если честно- то сам удивляюсь. Никогда такими изворотами не интересовался. А тут даже азарт появился... Эх, куда ж меня, в мои-то (хм...) годы!
А с учетом дополнений [42] и утечки памяти нет.
Но тогда приходится проверять некоторые условия в деструкторе, так как конструктор полностью не отработал. Но обычно (я про себя) такие проверки идут в любом деструкторе.


 
Тимохов ©   (2004-04-23 15:02) [46]


> Sha ©   (23.04.04 14:58) [44]

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

Порекоммендуйте что-нибудь почитать про эти преслувутые паттерны (покороче)?
Такое ощущение, что их действительно нужно знать, если уж на них дают задачи.


 
Тимохов ©   (2004-04-23 15:04) [47]


> Locker   (23.04.04 15:00) [45]

Жутко удивлен, но он действительно работает.
Надо понять в чем тут подвох, т.к. все-таки это какое имхо варварское отношение к дельфи :)))


 
Игорь Шевченко ©   (2004-04-23 15:08) [48]


> Порекоммендуйте что-нибудь почитать про эти преслувутые
> паттерны (покороче)?


Классика: Gang of Four Паттерны проектирования. (www.yandex.ru)


 
Sha ©   (2004-04-23 15:08) [49]

> Тимохов ©   (23.04.04 15:02) [46]
http://community.borland.com/article/0,1410,22576,00.html
http://www.castle-cadenza.demon.co.uk/single.htm


 
Vuk ©   (2004-04-23 15:11) [50]

to Игорь Шевченко ©   (23.04.04 14:56) [43]:
>Поэтому содержательные деструкторы для таких объектов, например,
>освобождающие какие-то ресурсы, делать не надо.
Хм... А кто мешает в конструкторе и деструкторе проверять тот же самый счетчик вызовов, который проверяется в New/FreeInstance?


 
Locker   (2004-04-23 15:13) [51]

>все-таки это какое имхо варварское отношение к дельфи

Согласен. Варварское. Лезть внутрь методов через указатели - варварство. Рабочее варварство.

Тут еще на какой-то ветке было обсуждение protected и private разделов. Это я к тому, что если захочешь - и в Private, и в Protected залезешь.

P.S. А, может, не варварство? Может, все-же хирургия? :)

P.P.S. Кстати... константа в конструкторе (с получением доступа через указатель) - случаем не аналог переменной класса (в том же C++)?


 
nikkie ©   (2004-04-23 15:14) [52]

>[44] Sha
странные какие-то требования. имхо, это не требования к паттерну Singleton (еще бы - откуда паттерн про NewInstance знает?), а ограничения, наложенные конкретной реализацией THSSingleton.


 
Андрей Сенченко ©   (2004-04-23 15:18) [53]

Хмм  ...

Издательство: "Питер"
Год издания: 2001, страниц: 368

Её вообще еще реально в продаже найти ?


 
Тимохов ©   (2004-04-23 15:20) [54]


> P.P.S. Кстати... константа в конструкторе (с получением
> доступа через указатель) - случаем не аналог переменной
> класса (в том же C++)?

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


 
Игорь Шевченко ©   (2004-04-23 15:23) [55]

Vuk ©   (23.04.04 15:11)
nikkie ©   (23.04.04 15:14)

С одной стороны, никто не мешает. Перенести счетчик ссылок в protected и проверять. С другой стороны лично мне такая реализация не нравится, когда в каждом деструкторе потомка надо проверять счетчик ссылок для выполнения каких-то действий. Класс этот изначально задумывался, как некий предок для хранения настроек (TSettings), поэтому содержательные деструкторы в нем не планировались.


 
Игорь Шевченко ©   (2004-04-23 15:24) [56]

Андрей Сенченко ©   (23.04.04 15:18) [53]

Я в магазине на "Войковской" видел.


 
SergLight ©   (2004-04-23 15:25) [57]


> Издательство: "Питер"
> Год издания: 2001, страниц: 368

У меня год издания 2003 (Серия "Библиотека программирования")


 
nikkie ©   (2004-04-23 15:26) [58]

>Класс этот изначально задумывался, как некий предок для хранения настроек (TSettings), поэтому содержательные деструкторы в нем не планировались.
как вариант: глобальная переменная, создаем объект в initialization, разрушаем в finalization, никто больше его не создает. зачем себе придумывать проблемы, чтобы потом их мужественно преодолевать?


 
Sha ©   (2004-04-23 15:27) [59]

> Vuk ©   (23.04.04 15:11) [50]
> А кто мешает в конструкторе и деструкторе проверять тот же
> самый счетчик вызовов, который проверяется в New/FreeInstance?

> nikkie ©   (23.04.04 15:14) [52]
> это не требования к паттерну Singleton (еще бы - откуда
> паттерн про NewInstance знает?), а ограничения, наложенные
> конкретной реализацией THSSingleton.

Просто значительно удобнее все проверять в одном месте.
Лично мне :)


 
vuk ©   (2004-04-23 15:29) [60]

to Игорь Шевченко ©   (23.04.04 15:23) [55]:
>Перенести счетчик ссылок в protected и проверять.
Ну не обязательно. Можно и в private оставить, сделав доступ на чтение через функцию, чтобы своим же шаловливым ручкам заранее не дать в потомках вмешаться в механизм. :o)


 
Игорь Шевченко ©   (2004-04-23 15:36) [61]

nikkie ©   (23.04.04 15:26)

Можно и так, как ты предлагаешь. Возможно разные пути решения проблемы (если проблема есть вообще). Кстати, можно проверять счетчик ссылок в перекрытом событии BeforeDestruction и если не равно 0, то вызывать Abort. А увеличивать счетчик ссылок в AfterConstruction, например.


 
Игорь Шевченко ©   (2004-04-23 15:48) [62]

vuk ©   (23.04.04 15:29)
nikkie ©   (23.04.04 15:26)

Раз зашел такой разговор, то подразумевается, что и в конструкторе надо запретить создание/выделение каких-то ресурсов больше одного раза ? У кого-то есть готовый способ ?

vuk ©   (23.04.04 15:29)

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


 
Игорь Шевченко ©   (2004-04-23 16:05) [63]


> Кстати, можно проверять счетчик ссылок в перекрытом событии
> BeforeDestruction и если не равно 0, то вызывать Abort


Не годится. А жаль


 
Sha ©   (2004-04-23 16:10) [64]

> Игорь Шевченко ©   (23.04.04 15:48) [62]
> Раз зашел такой разговор, то подразумевается, что и в
> конструкторе надо запретить создание/выделение каких-то
> ресурсов больше одного раза ? У кого-то есть готовый способ ?

Проще тогда генерировать исключение, как в http://www.castle-cadenza.demon.co.uk/single.htm


 
Игорь Шевченко ©   (2004-04-23 16:31) [65]

Sha ©   (23.04.04 16:10)

Хотелось бы прозрачно. Как вариант: vuk ©   (23.04.04 15:29) [60] , но получается, что потомки знают о механизме реализации предка, что тоже плохо


 
han_malign ©   (2004-04-23 16:39) [66]

>счетчика ссылок в деструкторе потомка
- если пошел разговор о потомках, то кто мешает еще раз перекрыть XXXInstance - так что разговор, на самом деле, ни о чем...

>запретить создание/выделение каких-то ресурсов больше одного раза
- можно конечно стек раскрутить - но это, IMHO, грубо - кулхацкерство одно... (по моему, достаточно Inc(ESP,4), хотя если фреймы  включены(или оптимизация выключена, и/или есть локальные переменные) - надо смотреть, но , кажись, ESP:=EBP[EBP](или просто EBP+4, если без фреймов, но с локальными)(разруливается через $IFOPT) - но это все надо смотреть, на вскидку утверждать не берусь)
- а вот с деструктором уже намного хуже...


 
han_malign ©   (2004-04-23 16:48) [67]

кстати, для HSSingleton можно без критической секции(ее таки инициализировать нужно), хотя, я сам постоянно забываю про - весьма полезные - InterlockedIncrement/Decrement...


 
Sha ©   (2004-04-23 16:53) [68]

han_malign ©   (23.04.04 16:48) [67]
В этом случае придется считать в отрицательную сторону :)


 
Sha ©   (2004-04-23 16:55) [69]

...начиная с 1


 
Игорь Шевченко ©   (2004-04-23 17:04) [70]


> можно без критической секции, я сам постоянно забываю про - весьма полезные - InterlockedIncrement/Decrement...


Не уверен


 
Sha ©   (2004-04-23 17:15) [71]


var
 Key: integer= 1;

class function THSSingleton.NewInstance: TObject;
begin;
 if InterLockedDecrement(Key)>=0
 then Instance:=THSSingleton(inherited NewInstance);
 Result:=Instance;
 end;

procedure THSSingleton.FreeInstance;
begin;
 if InterLockedIncrement(Key)>=0
 then begin;
   inherited;
   Instance:=nil;
   end;
 end;


 
Digitman ©   (2004-04-23 17:19) [72]

мьютексы, слава богу -  именованые объекты .. в их имени можно хранить Id процесса в строковом виде

"глобальность" переменной - понятие растяжимое ... гораздо более точное определение - область видимости и время жизни переменной ... она м.б. "видима" в пределах тек.модуля, и этого вполне достаточно для ответа на вопрос при собеседовании, ибо переменная не глобальна в контексте проекта и "жива" в теч.времени жизни процесса ехе-проекта (об этом, надеюсь, не упоминалось в вопросе)


 
Sha ©   (2004-04-23 17:20) [73]

поправка:
procedure THSSingleton.FreeInstance;
begin;
 InterLockedDecrement(Key);
 if InterLockedIncrement(Key)>=0
 then begin;
   inherited;
   Instance:=nil;
   end;
 InterLockedIncrement(Key);
 end;


 
Игорь Шевченко ©   (2004-04-23 17:27) [74]

Sha ©   (23.04.04 17:15)

Да, спасибо, вариант. Только читать непривычно :)


 
Sha ©   (2004-04-23 17:38) [75]

Но вариант с критической секцией мне нравится больше :)
он будет работать для нескольких потоков.
При доступе к моему варианту из нескольких потоков
два объекта не создастся, но возможен вариант, когда
второй поток может получить nil вместо адреса создаваемого
другим потоком объекта.


 
Verg ©   (2004-04-23 18:21) [76]


> Sha ©   (23.04.04 17:38) [75]


В данном случае крит.с не нужна в полном фунциональном объеме (рекурсивные вхождения). Так что, если нравится InterLocked..., то можно и с ними.

var Key : integer = 0;

...
 while InterLockedExchange(Key, 1) = 1 do sleep();
 // вошли в "КС"
 InterLockedExchange(Key,0);// вышли...

Можно и евентом с автосбросом, тогда и цикла со sleep не надо...


 
Sha ©   (2004-04-23 19:18) [77]

Verg ©   (23.04.04 18:21) [76]
Sleep не так красиво, а с Event мудренее и тяжелее:
крит. секция проскакивает почти всегда без wait"ов.


 
Verg ©   (2004-04-23 19:36) [78]


> Sleep не так красиво, а с Event мудренее и тяжелее:


Может и так - это дело вкуса:) Зато event можно именовать и сделать доступным и другим процессам (так, к слову)....

var Key : THandle; // createevent(nil, false, true, ....) (OpenEvent(....))

................
WaitForSingleObject(Key, INFINITE);
// вошли в "КС"
SetEvent(Key);// вышли...

Не так уж и "мудренее"...


 
Sha ©   (2004-04-23 19:47) [79]

Verg ©   (23.04.04 19:36) [78]
Я бы добавил try-finally.
Но, как уже говорил, предпочитаю крит.секцию, она менее ресурсоемка.


 
Verg ©   (2004-04-23 19:58) [80]


> она менее ресурсоемка.


Да? Есть основания так предпологать?
Я бы не осмелился....
Если она ведет учет того, какой поток именно ее захватил для обеспечния счетчика повторных вхождений, при этом таки заводит Event для ожидания освобождения, то уж всяко на "один квант" стоит дороже.
Не знаю точно про Windows, но опыт собственных "синхронизаторов" подсказывает, что критические секции обходятся несколько дороже, нежели элементарные "стоп - я сброшен".

Насчет try-finally - тут я полностью с тобой согласен :)) Просто за последние несколько дней на форумах у меня появилось ущущение, что эти блоки очень многие не любят, предпочитая goto и проч. :))))))))))



Страницы: 1 2 3 вся ветка

Форум: "Потрепаться";
Текущий архив: 2004.05.16;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.62 MB
Время: 0.098 c
3-1082348585
Layner
2004-04-19 08:23
2004.05.16
Вставка записи в табл. на одном MS SQL сервере должно зеркально


9-1059490261
Rooo
2003-07-29 18:51
2004.05.16
Как поставить GlScene 09b на Delphi 7?


3-1082198765
Relaxxx
2004-04-17 14:46
2004.05.16
Вопрос по SQL!!!


14-1082878046
Daniel
2004-04-25 11:27
2004.05.16
Локальная и глобальная сеть. Безопасон ли?


1-1083052445
Ivolg
2004-04-27 11:54
2004.05.16
Memo





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский