Перейти к содержанию

Подскажите формулу delphi 7


Рекомендуемые сообщения

pictureForm:=TPictureForm.Create ...

try

pictureForm.ShowModal;

finally

pictureForm.Free;

end;

раз пошла такая пьянка.... :)


try
pictureForm:=TPictureForm.Create ...
pictureForm.ShowModal;
finally
pictureForm.Free;
end;

Ссылка на комментарий

прохожий, давненько не писал в на дельфях, но насколько помню это корректно... В чем же проблема? Во всяком случае обработку исключения создания объекта точно нужно отлавливать..

Ссылка на комментарий
В чем же проблема?

в понимании, уважаемый.

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

а если учесть, что повторить иногда бывает трудно, ведь пример примитив,то и появляются любимые "кодерские" байки про фичи и т.п.

метод Free в коде:

try
pictureForm:=TPictureForm.Create ...
pictureForm.ShowModal;
finally
pictureForm.Free;
end;

будет выполняться даже когда переменная не будет содержать ссылку на объект, а разве нет?

и посему, код приведенный комрадом прохожий верный, а ваш нет.

обработку исключения

вами приведенном коде except, увы, уже не поможет. как его не прикручивай или костылем не вбивай.

давненько не писал в на дельфях,

это лишнее, ну вы же понимаете. =)

с уважением.

Ссылка на комментарий

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

pictureForm:=TPictureForm.Create ...
try
pictureForm.ShowModal;
finally
pictureForm.Free;
end;

и

try
pictureForm:=TPictureForm.Create ...
pictureForm.ShowModal;
finally
pictureForm.Free;
end;

В случае ошибки ошибки создания pictureForm вылетят оба, так что оба из них неверны, во всех остальных случаях будут работать одинаково. Однако сразу видно что я хотел сказать переместив создание объекта в блок try - проверку на случай ошибки в создании объекта и забыл всего лишь перенести и Free в тот же блок, либо чуток дополнить добавив вначале pictureForm:=nil; и в finally условие if (pictureForm<>nil) ...

Добавлено спустя 2 минуты 41 секунду:

ps. Особенно умиляет ваш сарказм, учитывая то, что я объяснял, что нужно воспользоваться ОО, а вы тут влепили кучу к делу отношения не имеющего... Здесь речь не шла об обработке исключений.

Ссылка на комментарий

а вы считаете, что try except шлепать нужно вдоль и поперек?

в данном контексте мы рассматривали пример

procedure showImg(img), код которой в реальности может быть и без обертки except, да и в примере я не вижу смысла обрабатывать на уровне этой процедуры.

построение обработки исключительных ситуаций в приложение это отдельный слой проектирования.

ну а вы еще предлагаете добавить абсолютно ненужный код, что бы избежать аксецвиолешн и только из за того что неверно используете try finally, а это костыль, как не крути.

ну если вам все одно, не путайте людей. право же, посмотри документацию.

желание придраться

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

и это относится не только к Delphi, и не только созданию освобождению ресурсов, а так же к "парным" вызовам. например методы BeginUpdate - EndUpdate, Open - Close и т.п.

если есть желание продолжить разговор, то думаю ему в самое время переместиться в ЛС.

Добавлено спустя 1 минуту 23 секунды:

тут влепили кучу к делу

вам указали на ошибку. а дальше ваше дело. лепите костыли.

с уважением

Ссылка на комментарий

coder, ну для начала читаем с самого начала, я вообще не предлагал вставлять сюда try, я лишь добавил что если уж и вставлять проверку, то и на создание тоже надо. Кроме того, считаю более логичным вставлять проверку в коде самого TPictureForm. (Всегда считал более красивым возвращение null/false на всякие Create и прочие функции, если произошло какое-либо исключение).

Добавлено спустя 1 минуту 54 секунды:

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

Ссылка на комментарий
try

пихать во внутрь try create а в finally Free - это ошибка. ну вы так и не поняли.

считаем, что все остались при своем лице, кому надо вывод сделали.

в любом случае в F1. документацию печатную после 3-ки не поставляли =(. (или нас обделили =)))

зы try добавил прохожий так как он там к месту. и его вариант верен =)

Ссылка на комментарий

coder, не будьте голословны(крайне негативное впечатление от таких заявлений), будьте добры, аргументируйте свое мнение. :)

зы. Насчет к месту ли, для этого сначала надо узнать есть ли try уже в самом методе showmodal у этого объекта...

Ссылка на комментарий

Ну что ж, видимо, аргументации не дождаться в связи с ее отсутствием :)

Тогда уж выскажусь в последний раз, так сказать развею мифы:

пихать во внутрь try create а в finally Free - это ошибка.

Это не более ошибка, чем предыдущий код от прохожего. А вставлять и create и free в try правильный подход, если вы сомневаетесь в данном классе.

Более того, если уж говорите об ЭксеССвиолеЙшн во Free(), значит тем более нужно Create и Free переносить в блок try.

Ссылка на комментарий
в блок try.

дык, никто не отклоняется от темы. вы утверждаете, что это верно:

try

pictureForm:=TPictureForm.Create ...

pictureForm.ShowModal;

finally

pictureForm.Free;

end;

ну теперь по порядку. под "ваши доказательства" вы предлагаете показать вам документацию и практику применения? (возьмем Delphi7 ). ок.

1. документация от борланда. жмем волшебную кнопку Ф1

delphi_ref.gif

не ахти объяснение? и если не понятно, идем дальше. к хелпу мы еще вернемся.

2. более творческий пересказ Ф1 от авторов:

ISBN 0672312840 (eng) ISBN 5845900166 (rus) глава 6 стр 173.

ISBN 9781598220032 (eng) chapter 13 page 289 (внешка)

Securing Resource Allocations

The reserved word try enables us to construct two different blocks: the exception handler block and the resource protection block. The exception handler block is created with the reserved word except and the resource protection block is created with the reserved word finally.

The syntax of the resource protection block in Delphi is:


finally
end;
try

In C++, the resource protection block looks like this:


{
}
__finally
{
}
try

The exception handling and resource protection blocks are used differently and act differently. While the statements in the exception handler execute only if the statements in the try block raise an exception, the statements in the finally block are always executed, even if no exceptions are raised by the statements in the try block. If an exception occurs in the try block, the control is passed to the finally block and cleanup code is executed. If no exceptions occur in the try block, the statements in the finally block are executed after the statements in the try block.

The proper way to use the resource protection block is to allocate or otherwise acquire the resource before the try block. After you have acquired the resource, write statements that use the resource inside the try block. When you're finished with the resource, you have to release it. The statements that release the resource should be placed in the finally block.


try
{ use the acquired resource }
finally
{ release the resource }
end;
{ acquire the resource }

The resource protection block is often used to ensure that dynamically created objects are released properly. For instance, you should always protect dynamic modal form creation with the try-finally block (see Listings 13-8A and 13-8B).

Listing 13-8A: Dynamically creating a form with resource protection, Delphi version


var
NewForm: TForm;
begin
NewForm := TForm.Create(Self);
try
NewForm.ShowModal;
finally
NewForm.Free;
end;
end;
procedure TForm1.CreateFormClick(Sender: TObject);

Listing 13-8B: Dynamically creating a form with resource protection, C++ version


{
TForm* NewForm = new TForm(this);
try
{
NewForm->ShowModal();
}
__finally
{
delete NewForm;
}
}
void __fastcall TForm1::CreateFormClick(TObject *Sender)

Listing 13-9 shows an even shorter way to dynamically create a form protected by the try-finally block.

Listing 13-9: Dynamically creating a form with resource protection, revisited


begin
with TForm.Create(Self) do
try
ShowModal;
finally
Free;
end;
end;
procedure TForm1.CreateFormShortClick(Sender: TObject);

The other difference between the exception handling and the resource handling blocks is that the resource handling block doesn't handle the exception. Thus, if an exception occurs, it will be passed to the first available exception handler. For instance, if you run the following code, the EDivByZero exception will cause the default exception handler to display the message box informing the user about the exception.


begin
with TForm.Create(Self) do
try
{ raises EDivByZero because the Tag property = 0 }
Caption := IntToStr(Top div Tag);
ShowModal;
finally
Free;
end;
end;
procedure TForm1.CreateFormShortClick(Sender: TObject);

If you want to handle the EDivByZero exception (or any other exception) inside the resource protection block, you have to write a nested exception handler block. The following listing shows how to write a nested exception handler inside the resource protection block. You can also nest resource protection blocks inside other resource protection blocks or exception handling blocks.

Listing 13-10: Nested blocks


begin
with TForm.Create(Self) do
try
try
Caption := IntToStr(Top div Tag);
except
on EDivByZero do Caption := 'Tag = 0';
end;

ShowModal;
finally
Free;
end;
end;
procedure TForm1.CreateFormClick(Sender: TObject);

...

http://books.google.ru/books?id=dOvw6h84qvwC&pg=PA289&lpg=PA633#v=onepage&q=&f=true

не отличаются друг от друга и не противоречат линии "партии" Borland. и опять не то?

3. шаблоны кода (code templates) Delphi. в редакторе кода Delphi 7 ctrl + J далее жмем t, видим trycf , выбрали и enter. получаем что то такое :


try

finally
variable.Free;
end;
variable := typename.Create;

понятно к чему Borland клонит, а остальным ? нет? да мало что они в шаблонах написали и кто написал, "индусы" где только не работают. смотрим дальше.

4. исходники от Borland . %Delphi7%\ source\vcl. исходники режу, уменьшая размер и выбираю "интересное".

не только на создание и удаление ресурсов, как говорил выше, и для "парных" методов и операций:


var ...

begin

...
Working := TBitmap.Create;
try
Working.Width := EdgeWidth;
Working.Height := FTabHeight;
MaskColor := clOlive;
...

finally
Working.Free;
end;
...
end;
procedure TTabSet.CreateEdgeParts;


procedure TThemeServices.PaintBorder(Control: TWinControl; EraseLRCorner: Boolean);
var ...

begin
...
DC := GetWindowDC(Handle);
try
EmptyRect := DrawRect;
if EraseLRCorner then
begin
...

finally
ReleaseDC(Handle, DC);
end;

...
end;


function CopyConfFile(Source, Target: string): Boolean;
var
List: TStrings;
IniIn, IniOut: TMemIniFile;
begin
List := TStringList.Create;
try
IniIn := TMemIniFile.Create(Source);
try
IniOut := TMemIniFile.Create(Target);
try
IniIn.GetStrings(List);
IniOut.SetStrings(List);
IniOut.UpdateFile;
Result := True;
finally
IniOut.Free;
end;
finally
IniIn.Free;
end;
finally
List.Free;
end;
end;


function TPrinter.GetPrinters: TStrings;
var ...

begin
...

GetMem(Buffer, Count);
try
if not EnumPrinters(Flags, nil, Level, PByte(Buffer), Count, Count, NumInfo) then
Exit;
PrinterInfo := Buffer;
...

finally
FreeMem(Buffer, Count);
end;
...

end;


procedure TMenuItem.AdvancedDrawItem(ACanvas: TCanvas; ARect: TRect;
State: TOwnerDrawState; TopLevel: Boolean);
const ...

begin
...
Glyph := TBitmap.Create;
try
Glyph.Transparent := True;
Glyph.Handle := LoadBitmap(0, PChar(OBM_CHECK));
OldBrushColor := Font.Color;
Font.Color := clBtnText;
Draw(GlyphRect.Left + (GlyphRect.Right - GlyphRect.Left - Glyph.Width) div 2 + 1,
GlyphRect.Top + (GlyphRect.Bottom - GlyphRect.Top - Glyph.Height) div 2 + 1, Glyph);
Font.Color := OldBrushColor;
finally
Glyph.Free;
end;

...
end;


procedure TDockTree.PaintSite(DC: HDC);
var ...

begin
Canvas := TControlCanvas.Create;
try
Canvas.Control := FDockSite;
Canvas.Lock;
try
Canvas.Handle := DC;
try
for I := 0 to FDockSite.ControlCount - 1 do
begin
Control := FDockSite.Controls[I];
...

end;
finally
Canvas.Handle := 0;
end;
finally
Canvas.Unlock;
end;
finally
Canvas.Free;
end;

end;


procedure TCustomMaskEdit.SetCursor(Pos: Integer);
const ...

begin
...
FSettingCursor := True;
try
SendMessage(Handle, WM_KEYDOWN, ArrowKey[UseRightToLeftAlignment], 1);
SendMessage(Handle, WM_KEYUP, ArrowKey[UseRightToLeftAlignment], 1);
finally
FSettingCursor := False;
end;
...
end;


constructor TDockTree.Create(DockSite: TWinControl);
var ...
begin
...
BeginUpdate;
try
for I := 0 to DockSite.ControlCount - 1 do
InsertControl(DockSite.Controls[I], alLeft, nil);
FTopZone.ResetChildren;
finally
EndUpdate;
end;

...
end;


procedure TStringGridStrings.Assign(Source: TPersistent);
var ...

begin
...
BeginUpdate;
Max := TStrings(Source).Count - 1;
if Max >= Count then Max := Count - 1;
try
for I := 0 to Max do
begin
Put(I, TStrings(Source).Strings[I]);
PutObject(I, TStrings(Source).Objects[I]);
end;
finally
EndUpdate;
end;
...

end;


procedure TCustomImageList.CopyImages(Value: HImageList; Index: Integer = -1);
var
I: Integer;
Image, Mask: TBitmap;
ARect: TRect;
begin
ARect := Rect(0, 0, Width, Height);
BeginUpdate;
try
Image := TBitmap.Create;
try
with Image do
begin
Height := FHeight;
Width := FWidth;
end;
Mask := TBitmap.Create;
try
with Mask do
begin
Monochrome := True;
Height := FHeight;
Width := FWidth;
end;
for I := 0 to ImageList_GetImageCount(Value) - 1 do
if (Index = -1) or (Index = I) then
begin
with Image.Canvas do
begin
FillRect(ARect);
ImageList_Draw(Value, I, Handle, 0, 0, ILD_NORMAL);
end;
with Mask.Canvas do
begin
FillRect(ARect);
ImageList_Draw(Value, I, Handle, 0, 0, ILD_MASK);
end;
Add(Image, Mask);
end;
finally
Mask.Free;
end;
finally
Image.Free;
end;
finally
EndUpdate;
end;
end;


procedure TSessionList.GetSessionNames(List: TStrings);
var
I: Integer;
SList: TList;
begin
List.BeginUpdate;
try
List.Clear;
SList := FSessions.LockList;
try
for I := 0 to SList.Count - 1 do
with TSession(SList[I]) do
List.Add(SessionName);
finally
FSessions.UnlockList;
end;
finally
List.EndUpdate;
end;
end;

ну кто нам Borland, так? там диктатура. им сказали жать ctrl+J, они и давят.

5. мы за демократию. тем более, в одной финской поговорке говорится: "При достаточном количестве глаз, все ошибки лежат на поверхности" ©.

http://www.delphi-jedi.org/ беру одну из частей проекта: JCL- http://jcl.delphi-jedi.org/. сырцы забираем с http://sourceforge.net/projects/jcl/

идем в каталог \source\common\


function TJclAbstractContainerBase.ObjectClone: TObject;
var
NewContainer: TJclAbstractContainerBase;
begin
{$IFDEF THREADSAFE}
ReadLock;
try
{$ENDIF THREADSAFE}
NewContainer := CreateEmptyContainer;
AssignDataTo(NewContainer);
Result := NewContainer;
{$IFDEF THREADSAFE}
finally
ReadUnlock;
end;
{$ENDIF THREADSAFE}
end;

...

procedure TJclAnsiStrAbstractCollection.AppendToStrings(Strings: TJclAnsiStrings);
var
It: IJclAnsiStrIterator;
begin
It := First;
Strings.BeginUpdate;
try
while It.HasNext do
Strings.Add(It.Next);
finally
Strings.EndUpdate;
end;
end;


procedure TJclAnsiStrings.LoadFromFile(const FileName: TFileName);
var
Stream: TStream;
begin
Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
LoadFromStream(Stream);
finally
Stream.Free;
end;
end;


function TJclIntfBinaryTreeIterator.Right: IInterface;
begin
{$IFDEF THREADSAFE}
FOwnTree.ReadLock;
try
{$ENDIF THREADSAFE}
Result := nil;
if FCursor <> nil then
FCursor := FCursor.Right;
if FCursor <> nil then
Result := FCursor.Value
else
if not FOwnTree.ReturnDefaultElements then
raise EJclNoSuchElementError.Create('');
{$IFDEF THREADSAFE}
finally
FOwnTree.ReadUnlock;
end;
{$ENDIF THREADSAFE}
end;


function TJclCompressionStreamFormats.FindCompressFormat(const AFileName: TFileName): TJclCompressStreamClass;
var
IndexFormat, IndexFilter: Integer;
Filters: TStrings;
AFormat: TJclCompressStreamClass;
begin
Result := nil;
Filters := TStringList.Create;
try
for IndexFormat := 0 to CompressFormatCount - 1 do
begin
AFormat := CompressFormats[IndexFormat];
StrTokenToStrings(AFormat.StreamExtensions, DirSeparator, Filters);
for IndexFilter := 0 to Filters.Count - 1 do
if StrMatches(Filters.Strings[IndexFilter], StrLower(AFileName)) then
begin
Result := AFormat;
Break;
end;
if Result <> nil then
Break;
end;
finally
Filters.Free;
end;
end;
...

procedure InternalCompress(SourceStream: TStream; CompressStream: TJclCompressStream;
ProgressCallback: TJclCompressStreamProgressCallback; UserData: Pointer);
var
SourceStreamSize, SourceStreamPosition: Int64;
Buffer: Pointer;
ReadBytes: Integer;
EofFlag: Boolean;
begin
SourceStreamSize := SourceStream.Size; // source file size
SourceStreamPosition := 0;

GetMem(Buffer, JclDefaultBufferSize + 2);
try
// ZLibStream.CopyFrom(SourceStream, 0 ); // One line way to do it! may not
// // be reliable idea to do this! also,
// //no progress callbacks!
EofFlag := False;
while not EofFlag do
begin
if Assigned(ProgressCallback) then
ProgressCallback(SourceStreamSize, SourceStreamPosition, UserData);

ReadBytes := SourceStream.Read(Buffer^, JclDefaultBufferSize);
SourceStreamPosition := SourceStreamPosition + ReadBytes;

CompressStream.WriteBuffer(Buffer^, ReadBytes);

// short block indicates end of zlib stream
EofFlag := ReadBytes < JclDefaultBufferSize;
end;
//CompressStream.Flush; (called by the destructor of compression streams
finally
FreeMem(Buffer);
end;
if Assigned(ProgressCallback) then
ProgressCallback(SourceStreamSize, SourceStreamPosition, UserData);
end;


function CompareFiles(const FileA, FileB: TFileName; BufferSize: Longint): Boolean;
var
A, B: TStream;
begin
A := TFileStream.Create(FileA, fmOpenRead or fmShareDenyWrite);
try
B := TFileStream.Create(FileB, fmOpenRead or fmShareDenyWrite);
try
Result := CompareStreams(A, B, BufferSize);
finally
B.Free;
end;
finally
A.Free;
end;
end;


function SetBitmapColors(Bmp: TBitmap; const Colors: array of TColor; StartIndex: Integer): Integer;
type
TRGBQuadArray = array [Byte] of TRGBQuad;
PRGBQuadArray = ^TRGBQuadArray;
var
I, RGB: Integer;
ColorTable: PRGBQuadArray;
Count: Integer;
begin
Count := High(Colors)-Low(Colors)+1;
GetMem(ColorTable, Count * SizeOf(TRGBQuad));
try
for I := 0 to Count-1 do
with ColorTable^[I] do
begin
RGB := ColorToRGB(Colors[I]);
rgbBlue := GetBValue(RGB);
rgbGreen := GetGValue(RGB);
rgbRed := GetRValue(RGB);
rgbReserved := 0;
end;
Bmp.HandleType := bmDIB;
Result := GDICheck(SetDIBColorTable(Bmp.Canvas.Handle, StartIndex, Count, ColorTable^));
finally
FreeMem(ColorTable);
end;
end;


function GetLocalGroups(const Server: string; const Groups: TStrings): Boolean;
var
Err: NET_API_STATUS;
wServername: WideString;
Buffer: PByte;
Details: PLocalGroupInfo0;
EntriesRead, TotalEntries: Cardinal;
I: Integer;
begin
wServername := Server;
Err := RtdlNetLocalGroupEnum(PWideChar(wServername), 0, Buffer, MAX_PREFERRED_LENGTH,
EntriesRead, TotalEntries, nil);

if Err = NERR_SUCCESS then
begin
Details := PLocalGroupInfo0(Buffer);
Groups.BeginUpdate;
try
for I := 0 to EntriesRead - 1 do
begin
Groups.Add(Details^.lgrpi0_name);
Inc(Details);
end;
finally
Groups.EndUpdate;
end;
end;

RtdlNetApiBufferFree(Buffer);
Result := (Err = NERR_SUCCESS);
end;


function GetInteractiveUserName: string;
var
Handle: THandle;
Token: THandle;
User: PTokenUser;
{$IFDEF SUPPORTS_UNICODE}
Name, Domain: WideString;
{$ELSE ~SUPPORTS_UNICODE}
Name, Domain: AnsiString;
{$ENDIF ~SUPPORTS_UNICODE}
begin
Result := '';
if not IsWinNT then // if Win9x, then function return ''
Exit;
Handle := GetShellProcessHandle;
try
Token := 0;
Win32Check(OpenProcessToken(Handle, TOKEN_QUERY, Token));
try
User := nil;
QueryTokenInformation(Token, TokenUser, Pointer(User));
try
LookupAccountBySid(User.User.Sid, Name, Domain);
Result := Domain + '\' + Name;
finally
FreeMem(User);
end;
finally
CloseHandle(Token);
end;
finally
CloseHandle(Handle);
end;
end;

им также приказали жать Ctrl+J ? ну а то, смотрим:

открываем окно" about... ", что в меню help. удерживая кнопку alt набираем jedi .

им приказали =).

продолжаем дальше или хватит? или п.4-5 фальсификация.

6. магическая кнопка Ф1 могла бы быть более информативней. но всегда есть вероятность, что понимание написанного будет соответствовать второй части известной русской поговорки : "... . Если писан, то не читан. Если читан, то не понят. Если понят, то не так!" embarcadero решила изменить ситуацию и привлечь комьюнити для пополнения EDN, на понятном языке:

try…finally.

try…finally.

There were quite a few interesting comments made to this post from the other day that seemed to indicate that there is a little confusion out there regarding exceptions. More specifically, the try…finally construct.

I’ve seen some rather interesting twists on the use of try…finally that have made me pause and wonder why it was done that way. When programming with exceptions, you always have to be aware that at nearly any point and without warning, control could be whisked away to some far-off place. In many ways you have to approach and think about the problem very similarly to how you would in a multi-threaded scenario. In either case, you always have to keep in the back of your mind two (or more in the multi-threaded case) potential code paths. The first one is easy since that is the order in which you’re writing the code statements that define the overall logic and intent of your program. The other, and often forgotten code path is the exception execution path.

When an exception is raised (or "thrown" in the parlance of C++ and other similar languages) a lot of behind the scenes work is set into motion. I won’t be going into the details of exactly what is going on since that tends to be platform and language dependant. I’ll focus more on what happens from the programmers perspective and even more specifically the try…finally construct. One way to think of the try…finally block is that it is the programmer’s way of "getting in the way" of that secondary code execution path. However, it is also unique in that it also "gets in the way" of the normal code execution path. In the grand scheme of things, the try…finally block is one of the most used (and often mis-used) block types for programming with exceptions. I’d venture to say that in the typical application the ratio of try…finally blocks to try…except blocks is on the order of 100:1. But why use them at all and what are they good for? It’s all about resource management. Memory, files, handles, locks, etc… are all examples of the various resources your application uses and interacts with. The whole point of the try…finally block is to ensure an acquired resource is also properly handed back regardless of which execution path the application takes.

Let’s look at some common misuses of the try…finally block and examine them more closely.

var

Obj: TMyClass;

begin

try

Obj := TMyClass.Create;

finally

Obj.Free;

end;

end;

There’s a subtle problem here… Let’s follow the normal execution flow first. Control enters the try block, an instance of TMyClass is allocated and the constructor is called, control returns and the local variable, Obj, is assigned. Some operations are done with the Obj instance (the "…"), then control enters the finally block and the Obj instance is freed. So far so good, right? I mean, the memory is allocated and freed and all is well with the heap along with any other resources needed by the TMyClass instance (assuming it is a properly designed class, that is).

Now let’s look at the other possible flow of control. Control enters the try block, an instance of TMyClass is allocated and the constructor is called. Here is where something can go horribly wrong. When programming with exceptions, the possibilities are nearly endless as to what can happen during the call to the constructor. The most obvious is the case where the memory manager is unable to allocate enough space on the heap to hold the instance data for the new instance. An "Out of Memory" exception is raised. Hey, but that’s OK because the finally block will get in the way of the the exception control flow, right? Yep, that’s right. So memory was never allocated, the constructor was never called, local variable Obj was never assigned, and control is passed to the finally block which contains…. uh… Obj.Free; Do you see it now? Yep, that’s right, the Obj reference was never properly set. Because of that, the call to Obj.Free; is not good for the health of your application. Chances are that another exception is going to be raised which will supercede the original exception (most likely a more fatal and nasty one).

So how do we fix this? Hey I know! What if we just made sure to pre-initialize the Obj reference to nil (Obj := nil;)? Sure. You could do that, but that is just adds another line of code to your function. How can we arrange the above code to ensure that every time control is passed to the finally block regardless of which path of execution is used to get there? It’s actually very simple. Here’s the same block with that subtle change:

var

Obj: TMyClass;

begin

Obj := TMyClass.Create;

try

finally

Obj.Free;

end;

end;

But now the construction of the TMyClass instance isn’t protected! It doesn’t have to be and let’s examine why. From some of my previous posts regarding exception safety and the use of Assigned, we alluded to the fact that while the constructor of an object is executing, if any exception is raised the destructor will automatically be called, the object will be freed and the exception is allowed to continue on its merry way. There are essentially two main areas were things can go wrong. The first is during the actual allocation of the memory for the instance. If the memory manager is unable to find a block of free memory large enough to hold that instance, it will raise an "Out of Memory" exception. Since the instance was never actually allocated, there is no need to ever execute the Obj.Free; line of code. Since the try…finally block was never entered, Obj.Free will never be called. The other place where things can go wrong is in the object’s constructor. In this case the memory manager allocated the memory and then control was passed off to the the constructor that would begin to setup the instance. If something fatal happened along the way there, we know from those past articles that the destructor will automatically be called and the instance memory handed back to the memory manager for later re-use. Since the object was already freed and, again, control never entered the try…finally block, the Obj.Free; line is never executed. So in both of those scenarios, there was no need to touch the local Obj variable reference since the resources associated with the TMyClass instance were taken care of. If the memory allocation succeeds, the constructor runs to completion, then control will return and the local variable Obj will be assigned after which control will then enter the try…finally block. It is only at this point that you always want to make sure the TMyClass instance referenced by Obj is freed regardless of what happens next.

There are a lot of other interesting "twists" on the usage of try…finally and try…except blocks that I’ve seen over the years. The above case stands out in my mind as the most common mistake made. I’ll address some of the other cases in following posts. If you have any questions about certain common idioms and patterns that you’re not sure are exception aware, post some comments and maybe I’ll address them in future posts.

There are a lot of other interesting "twists" on the usage of try…finally and try…except blocks that I’ve seen over the years. The above case stands out in my mind as the most common mistake made. - собственно так и есть.

такие вот картинки из жизни, хотя можно было остановиться и в п.1, все дело в пони... , ну вы поняли =).

напоследок

1. создайте проект VCL. сохраняем.

2. на форму разместите TButton , "кликнем" по ней. создается обработчик события OnClick: procedure TForm1.Button1Click(Sender: TObject); - ну или что то того.

3. используя магию копипаста доводим до вида:


var
t: TTest;
begin
//t := TTest.Create; - так верно
try
t := TTest.Create; // - а это нет
MessageDlg('Понятно ?',mtInformation,mbOKCancel,0);
finally
t.Free;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);

4. повторим призыв копипаста, добавим ниже:


constructor TTest.Create;
begin
raise Exception.Create('тест провален');
end;

5. в разделе interface добавим, известным магическим заклинанием Ctrl + C Сtrl + V


constructor Create();
end;
  TTest = class


unit Unit1;

interface

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

type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

TTest = class
constructor Create();
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
t: TTest;
begin
//t := TTest.Create; - так верно
try
t := TTest.Create; // - а это нет
MessageDlg('Понятно ?',mtInformation,mbOKCancel,0);
finally
t.Free;
end;
end;

constructor TTest.Create;
begin
raise Exception.Create('тест провален');
end;

end.

6. не запускаем, а только компилируем. ctrl+f9

неважно, что получим варнинг - гавно случается, для настоящих "кодеров" это не повод для суеверий. Code Monkey добавят чего "следует", натыкая Excalibur-усы костыли, главное же работает. им, как говорится, "бог навстречу".

7. открываем проводник и идем к нашему файлику.

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

9.

раз загадали, кликаем и запускаем.

10.

ц е н о к

с уважением

развею мифы:

это в другой передаче,

337141594.jpg

хотя встречаются и тут

Ссылка на комментарий

coder, я просто балдею от кол-ва времени, которое было вами потрачено на совершенно не те вещи... Во-первых, научитесь читать внимательно. Прочти хорошенько то, что я писал постом ранее и еще выше. Во-вторых, приводя код заглядывайте в него сами. В-третьих, vcl-код от борланда подразумевает что ошибок при создании их объекта произойти не может, это просто уверенность в своем коде. И, наконец, в-четвертых, если для вас привычно чтобы программы вылетали то продолжайте писать такой код, но все-таки советую воспользоваться моим советом и писать нормально.

Ссылка на комментарий

X-tender как раз вы и голословны в своих заблуждениях утверждениях

vcl-код от борланда подразумевает что ошибок при создании их объекта произойти не может, это просто уверенность в своем коде.

Код от борланда просто уверен, что ошибки могут произойти на любом ровном месте, и по этому весь код обернут в блок try..except, который передает управление стандартному обработчику исключительных ситуаций(который можно поменять). Далее весь конструктор обернут в блок try..except, который вызывает деструктор(по этому в любой нормальной книжке по ООП написано, чтоб деструктор по возможности не вызывал исключения и был готов к любому состоянию обьекта, в том числе и к не полностью созданному обьекту)

pictureForm:=TPictureForm.Create ...
try
pictureForm.ShowModal;
finally
pictureForm.Free;
end;

и

try
 pictureForm:=TPictureForm.Create ...
 pictureForm.ShowModal;
finally
 pictureForm.Free;
end;

В случае ошибки ошибки создания pictureForm вылетят оба, так что оба из них неверны, во всех остальных случаях будут работать одинаково.

Первый код в любом случае передаст обработчику исключений верную информацию, и предотвратит утечку памяти разблокирует ресурсы(собственно для этого тут и присутствует блок try..finally), т.е. код 100% правильный и так рекомендуется делать со всеми временными обьектам(выделенными ресурсами).

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

Однако сразу видно что я хотел сказать переместив создание объекта в блок try - проверку на случай ошибки в создании объекта и забыл всего лишь перенести и Free в тот же блок, либо чуток дополнить добавив вначале pictureForm:=nil; и в finally условие if (pictureForm<>nil)

...

на это утверждение вам четко и ясно ответил coder следующим же постом ,но по видимому вы ничего не поняли т.к. продолжили:

Более того, если уж говорите об ЭксеССвиолеЙшн во Free(), значит тем более нужно Create и Free переносить в блок try.

Как я уже сказал, весь код программы обернут в try..except, но по видимому иногда не достаточно стандартного обработчика ошибок, т.е нарушилась логика работы программы и надо чтото исправить и продолжить выполнение программы. Очевидно что содержимого блока try..finally не всегда достаточно чтобы исправить логику работы программы. Нужно обернуть код в try..except, в том месте программы, где можно чтото исправить(и это может быть не в том же методе, а в вызывающем). Т.е. назначение у операторов try..finally и try..except совершенно разное: у первого чтоб ненапортить ничего, а у второго чтоб попытаться исправить. И именно по этому это два разных оператора.

Во всяком случае обработку исключения создания объекта точно нужно отлавливать..
А вставлять и create и free в try правильный подход, если вы сомневаетесь в данном классе

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

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

Вы советуете использовать операторы не по назначению и пихать их куда только можно, везде прикручивать костыли.(см. Индусы:))

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

Ссылка на комментарий
vcl-код от борланда подразумевает что ошибок при создании их объекта произойти не может, это просто уверенность в своем коде

поржал, спасибо.


constructor TFileStream.Create(const FileName: string; Mode: Word; Rights: Cardinal);
begin
if Mode = fmCreate then
begin
inherited Create(FileCreate(FileName, Rights));
if FHandle < 0 then
raise EFCreateError.CreateResFmt(@SFCreateErrorEx, [ExpandFileName(FileName), SysErrorMessage(GetLastError)]);
end
else
begin
inherited Create(FileOpen(FileName, Mode));
if FHandle < 0 then
raise EFOpenError.CreateResFmt(@SFOpenErrorEx, [ExpandFileName(FileName), SysErrorMessage(GetLastError)]);
end;
end;

constructor TThread.Create(CreateSuspended: Boolean);
{$IFDEF LINUX}
var
ErrCode: Integer;
{$ENDIF}
begin
inherited Create;
AddThread;
FSuspended := CreateSuspended;
FCreateSuspended := CreateSuspended;
{$IFDEF MSWINDOWS}
FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), CREATE_SUSPENDED, FThreadID);
if FHandle = 0 then
raise EThread.CreateResFmt(@SThreadCreateError, [SysErrorMessage(GetLastError)]);
{$ENDIF}
{$IFDEF LINUX}
sem_init(FCreateSuspendedSem, False, 0);
ErrCode := BeginThread(nil, @ThreadProc, Pointer(Self), FThreadID);
if ErrCode <> 0 then
raise EThread.CreateResFmt(@SThreadCreateError, [SysErrorMessage(ErrCode)]);
{$ENDIF}
end;

constructor TDataModule.Create(AOwner: TComponent);
begin
GlobalNameSpace.BeginWrite;
try
CreateNew(AOwner);
if (ClassType <> TDataModule) and not (csDesigning in ComponentState) then
begin
if not InitInheritedComponent(Self, TDataModule) then
raise EResNotFound.CreateFmt(SResNotFound, [ClassName]);
if OldCreateOrder then DoCreate;
end;
finally
GlobalNameSpace.EndWrite;
end;
end;

советую воспользоваться

увольте-с.

за сим все, однако напомню вам:

Глупость — дар Божий, но не следует им злоупотреблять (с)

извините, но у меня есть подозрение, что вы путаете try ... finally c except.

Ссылка на комментарий

triwire, поражает отсутствие понимания собственных слов и незнание элементарных основ. Хорошенько подумайте, чем отличается А от B:


procedure showImg(img)
var pictureForm:TPictureForm;
begin
pictureForm:=TPictureForm.Create(img,dimensions);
pictureForm.ShowModal;
pictureForm.Free;
end;

от


procedure showImg(img)
var pictureForm:TPictureForm;
begin
pictureForm:=TPictureForm.Create(img,dimensions);
try
pictureForm.ShowModal;
finally
pictureForm.Free;
end;
end;

Когда разбересь, надеюсь, больше не будете приставать с глупостями.

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


log('Creating');
c:=TMyClass.Create(Self);
try
log('Show');
c.ShowModal;
finally
log('Finally:');
log('Free');
c.Free;
log('Doing something else:');
SomethingElse();
end;


try
log('Creating');
c:=TMyClass.Create(Self);
log('Show');
c.ShowModal;
log('Free');
c.Free;
finally
log('Finally:');
log('Doing something else:');
SomethingElse();
end;

Добавлено спустя 1 минуту 33 секунды:

за сим все, однако напомню вам:

Глупость — дар Божий, но не следует им злоупотреблять (с)

+100500, многократно :) Иногда умение читать от умения понимать, оказывается, сильно отличается... :)

Ссылка на комментарий
triwire, поражает отсутствие понимания собственных слов и незнание элементарных основ. Хорошенько подумайте, чем отличается А от B:


procedure showImg(img)
var pictureForm:TPictureForm;
begin
pictureForm:=TPictureForm.Create(img,dimensions);
pictureForm.ShowModal;
pictureForm.Free;
end;

от


procedure showImg(img)
var pictureForm:TPictureForm;
begin
pictureForm:=TPictureForm.Create(img,dimensions);
try
pictureForm.ShowModal;
finally
pictureForm.Free;
end;
end;

Когда разбересь, надеюсь, больше не будете приставать с глупостями

Я вами поражаюсь, но о вас позже.

Я еще раз говорю, что код В, в любом случае вызовет деструктор.

Код А, при ошибке в методе TPictureForm.ShowModal не вызывет деструктор pictureForm. Для примера перегрузите метод:


function TPictureForm.ShowModal:integer; override;
begin
result:=inherited ShowModal;
raise Exception.Create('ПРЕВЕД');
end;

что по сути, будет эквивалентно:


procedure showImg(img)
var pictureForm:TPictureForm;
begin
pictureForm:=TPictureForm.Create(img,dimensions);
pictureForm.ShowModal;
raise Exception.Create('ПРЕВЕД');
pictureForm.Free;
end;


function TCustomForm.ShowModal: Integer;
var
WindowList: Pointer;
SaveFocusState: TFocusState;
SaveCursor: TCursor;
SaveCount: Integer;
ActiveWindow: HWnd;
begin
CancelDrag;
if Visible or not Enabled or (fsModal in FFormState) or
(FormStyle = fsMDIChild) then
raise EInvalidOperation.Create(SCannotShowModal);
if GetCapture <> 0 then SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
ReleaseCapture;
Application.ModalStarted;
try
Include(FFormState, fsModal);
if (PopupMode = pmNone) and (Application.ModalPopupMode <> pmNone) then
begin
RecreateWnd;
HandleNeeded;
end;
ActiveWindow := GetActiveWindow;
SaveFocusState := Forms.SaveFocusState;
Screen.SaveFocusedList.Insert(0, Screen.FocusedForm);
Screen.FocusedForm := Self;
SaveCursor := Screen.Cursor;
Screen.Cursor := crDefault;
SaveCount := Screen.CursorCount;
WindowList := DisableTaskWindows(0);
try
Show;
try
SendMessage(Handle, CM_ACTIVATE, 0, 0);
ModalResult := 0;
repeat
Application.HandleMessage;
if Application.Terminated then ModalResult := mrCancel else
if ModalResult <> 0 then CloseModal;
until ModalResult <> 0;
Result := ModalResult;
SendMessage(Handle, CM_DEACTIVATE, 0, 0);
if GetActiveWindow <> Handle then ActiveWindow := 0;
finally
Hide;
end;
finally
if Screen.CursorCount = SaveCount then
Screen.Cursor := SaveCursor
else Screen.Cursor := crDefault;
EnableTaskWindows(WindowList);
if Screen.SaveFocusedList.Count > 0 then
begin
Screen.FocusedForm := Screen.SaveFocusedList.First;
Screen.SaveFocusedList.Remove(Screen.FocusedForm);
end else Screen.FocusedForm := nil;
if ActiveWindow <> 0 then SetActiveWindow(ActiveWindow);
RestoreFocusState(SaveFocusState);
Exclude(FFormState, fsModal);
end;
finally
Application.ModalFinished;
end;
end;

Поговорим далее:

Собственно зачем вы для какого простого примера, взяли такой сложных класс как TForm?

Судя по вашему недопониманию отличий, вы для проверки создавали исключение в событии (например в OnClick), и у вас конешно же разницы не наблюдалось.

Давайте я приведу пример:


procedure pictureForm.FormClick(Sender: TObject);
begin
raise Exception.Create('Ошибка в обработчике событий');
end;

procedure showImg(img)
var pictureForm:TPictureForm;
begin
try
pictureForm:=TPictureForm.Create(img,dimensions);
pictureForm.OnClick:=pictureForm.FormClick;
pictureForm.ShowModal;
pictureForm.Free;
except
raise Exception.Create('Ошибка в "основной" программе');
end;
end;

Можете комбинировать с первым примером и делать выводы.

А дело в том, что события в большинстве случаев вызываются не из вашего кода(В частности OnClick берет свои корни из user32.dll, и этой библиотеке нах не нужны ваши исключительные ситуации), и по этому весь обработчик событий завернут в try..except, который(если не установлено Application.OnException) выводит на экран MessageBox, и завершает обработку текущего сообщения(переходит к обработке следующего сообщения).

Т.е. из "основной" программы, блоком try..except, вы не поймаете ошибку в обработке сообщений.

И собственно вы правы, групость - пытаться переубедить такого дятла как вы.

Ссылка на комментарий

X-tender

//Вариант 0
procedure showImg(img)
var pictureForm:TPictureForm;
begin
pictureForm:=TPictureForm.Create(img,dimensions);
try
pictureForm.ShowModal;
finally
pictureForm.Free;
end;
end;

//Вариант 1
procedure showImg(img)
var pictureForm:TPictureForm;
begin
pictureForm:=TPictureForm.Create(img,dimensions);
pictureForm.ShowModal;
pictureForm.Free;
end;

//Вариант 2
procedure showImg(img)
var pictureForm:TPictureForm;
begin
try
pictureForm:=TPictureForm.Create(img,dimensions);
pictureForm.ShowModal;
finally
pictureForm.Free;
end;
end;

//Вариант 3
procedure showImg(img)
var pictureForm:TPictureForm;
begin
try
pictureForm:=TPictureForm.Create(img,dimensions);
pictureForm.ShowModal;
pictureForm.Free;
finally

end;
end;

//Говнокод 0
procedure showImg(img)
var pictureForm:TPictureForm;
begin
pictureForm:=nil
try
pictureForm:=TPictureForm.Create(img,dimensions);
pictureForm.ShowModal;
finally
if (pictureForm<>nil) then pictureForm.Free;
end;
end;

Вам был предложен(единственно верный в данном контексте) вариант 0, вы же утверждаете что он не верный.

Вами пока что было предложено четыре варианта:

Вариант 1 - исключительная ситуация в showModal не даст разблокировать ресурсы pictureForm.

Вариант 2 - исключительная ситуация в Create приведет к вызову 2 раза деструктора.

Вариант 3 - исключительная ситуация в showModal не даст разблокировать ресурсы pictureForm.

Говнокод 0 - говнокод

все остальные варианты разместить try..finally..end и create..showmodal..free, вообще не имеют смысла:)

Далее:

давненько не писал в на дельфях, но насколько помню это корректно... В чем же проблема? Во всяком случае обработку исключения создания

объекта точно нужно отлавливать..

Как вам уже писали, проблема не в дельфи, а в вашем понимании(проблема любых парных вызовов).

Тут же вы упомянули про обработку исключений(заметьте первым это зделали вы) при создании обьекта, и единственно рассово верным тут будет вариант:


var pictureForm:TPictureForm;
begin
...
try
...
pictureForm:=TPictureForm.Create(img,dimensions);
try
pictureForm.ShowModal;
finally
pictureForm.Free;
end;
except
...
end;
...
end;

ну для начала читаем с самого начала, я вообще не предлагал вставлять сюда try

try..finally вам предложили, потомучто вы в грубой форме упомянули про говнокод

Кроме того, считаю более логичным вставлять проверку в коде самого TPictureForm. (Всегда считал более красивым возвращение null/false на

всякие Create и прочие функции, если произошло какое-либо исключение).

Насчет к месту ли, для этого сначала надо узнать есть ли try уже в самом методе showmodal у этого объекта...

да, в showmodal есть try..finally, но это ничего не меняет, хоть есть он, хоть нету. Снаружи try..finally нужен для того чтоб гарантированно удалить обьект.

Более того, если уж говорите об ЭксеССвиолеЙшн во Free(), значит тем более нужно Create и Free переносить в блок try.

Ошибка в деструкторе, является критической ошибкой, и по сути исправить мы ничего уже не можем. т.е. придется констатировать факт критической ошибки и завершить программу. Соответственно блок try..except часто нах не нужен, проще это зделать в Application.OnException.

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

По факту - вы дятел, еще и опозорилсо.:)

Ссылка на комментарий
В чем же проблема?
метод Free в коде:

try
pictureForm:=TPictureForm.Create ...
pictureForm.ShowModal;
finally
pictureForm.Free;
end;

будет выполняться даже когда переменная не будет содержать ссылку на объект, а разве нет?

метод будет вызываться, но ошибки это не вызовет:

procedure TObject.Free;
begin
if Self <> nil then
Destroy;
end;

не будет вызван дестрой.

Добавлено спустя 1 минуту 57 секунд:

посему считаю, что прав оказался X-tender. код работоспособен.

ведь никто из вас так и не попытался протестить код.

Ссылка на комментарий

TolkienDRR

а вы уверены что у вас nil будет? проверьте сами код для телепатов есть выше.

вот даже х-тендер нет, он прикручивал такой "костыль"

либо чуток дополнить добавив вначале pictureForm:=nil; и в finally условие if (pictureForm<>nil)

Добавлено спустя 50 секунд:

ведь никто из вас так и не попытался протестить код

вам видео выложить или сами, у вас то есть дельфи =)

Ссылка на комментарий

coder, xD видео проблематично, т.к. огран на размер файлов, смогу скачать только ближе к ночеру. код в архиве и скрина будет достаточно.

Ссылка на комментарий

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

Вам напоследок TExceptObject от меня: http://slil.ru/28171065


var
o:TExceptObject;
begin
//TExceptObject.Create(RaiseExceptOnCreate,RaiseExceptOnTest,RaiseExceptOnDestroy:boolean);
o:=TExceptObject.Create(false,false,true);
ShowMessage('Created');
o.Test;
ShowMessage('Tested');
o.Free;
ShowMessage('Destroyed');
end;

Ссылка на комментарий
Гость
Эта тема закрыта для публикации ответов.
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...