Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2008.06.08;
Скачать: CL | DM;

Вниз

Освобождение ресурса в finally   Найти похожие ветки 

 
Arinyshka   (2008-04-23 12:17) [0]

Не подскажете еще один момент:
Есть процедура, выглядит примерно так

procedure TSetPayFrm.BtnAddImageClick(Sender: TObject);
var  TempBitmap:TBitmap;
begin
if not(opendialog1.Execute) then  exit;
try
 TempBitmap  := TBitmap.Create;
 TempBitmap.LoadFromFile(OpenDialog1.FileName);
finally
TempBitmap.Free;
end;
end;

На освобождение  TempBitmap.Free; выдает варнинг
[Warning] uSetPaymentMain.pas(313): Variable "TempBitmap" might not have been initialized
Не смертельно, но непонятно... почему варнинг? При изменениии условия и включении всей конструкции в один блок begin..end ситуация не менялась.


 
Рамиль ©   (2008-04-23 12:18) [1]

TempBitmap  := TBitmap.Create;
try
TempBitmap.LoadFromFile(OpenDialog1.FileName);
finally
TempBitmap.Free;
end;


 
Arinyshka   (2008-04-23 12:21) [2]

упс :) чувствую себя дура дурой :) Ну конечно! спасибо :)))))


 
Ega23 ©   (2008-04-23 12:21) [3]


> Не смертельно, но непонятно... почему варнинг?


Потому что если в конструкторе произойдёт исключение, то TempBitmap будет равен nil. А после ты попадаешь на finally, где вызываешь free.
Create нужно выносить за блок try..finally


 
{RASkov} ©   (2008-04-23 12:22) [4]

> но непонятно... почему варнинг?

Потому как создание объекта в защищенной секции, а уничтожение принудительное в финале.... поэтому компилятор и говорит, что объект может и не создасться и в финале будет АВ.
Решение в [1]... т.е. создание вынести из защитного блока...


 
{RASkov} ©   (2008-04-23 12:22) [5]

:)


 
{RASkov} ©   (2008-04-23 12:23) [6]

> Потому что если в конструкторе произойдёт исключение, то
> TempBitmap будет равен nil. А после ты попадаешь на finally,
> где вызываешь free.

Если в конструкторе будет ошибка то в секцию финал мы не попадем вовсе...


 
{RASkov} ©   (2008-04-23 12:24) [7]

> [6] {RASkov} ©   (23.04.08 12:23)

.... это если использовать код из [1]


 
Palladin ©   (2008-04-23 12:25) [8]


> Ega23 ©   (23.04.08 12:21) [3]
> то TempBitmap будет равен nil. А после ты попадаешь на finally,
>  где вызываешь free.


ха... если бы он был равен Nil.. он не равен Nil, Nil для Free несмертелен, TempBitmap будет неинициализирован то бишь мусор, а вот это для Free уже критично


 
Ega23 ©   (2008-04-23 12:30) [9]


> Если в конструкторе будет ошибка то в секцию финал мы не
> попадем вовсе...
>


Да ну????


unit Unit2;

interface

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

type

 TMyObj = class
 public
   constructor Create(const RaiseException : Boolean = False);
   procedure DoWork;
 end;

 TForm2 = class(TForm)
   Button1: TButton;
   Label1: TLabel;
   Button2: TButton;
   procedure Button1Click(Sender: TObject);
   procedure Button2Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

var
 Form2: TForm2;

implementation

{$R *.dfm}

{ TMyObj }

constructor TMyObj.Create(const RaiseException: Boolean);
begin
 if RaiseException then
   raise Exception.Create("TMyObj.Create");
end;

procedure TMyObj.DoWork;
begin
 ShowMessage("TMyObj.DoWork");
end;

procedure TForm2.Button1Click(Sender: TObject);
var
 obj : TMyObj;
begin
 Label1.Caption := "";
 obj := TMyObj.Create(True);
 try
   obj.DoWork;
 finally
   Label1.Caption := "попали в finally";
   obj.Free;
 end;
end;

procedure TForm2.Button2Click(Sender: TObject);
var
 obj : TMyObj;
begin
 Label1.Caption := "";

 try
   obj := TMyObj.Create(True);
   obj.DoWork;
 finally
   Label1.Caption := "попали в finally";
   obj.Free;
 end;

end;

end.


 
Ega23 ©   (2008-04-23 12:32) [10]


> ха... если бы он был равен Nil.. он не равен Nil, Nil для
> Free несмертелен, TempBitmap будет неинициализирован то
> бишь мусор, а вот это для Free уже критично
>


Согласен, неточно выразился.


 
Рамиль ©   (2008-04-23 12:34) [11]


> Ega23 ©   (23.04.08 12:32) [10]

Сам попался? :)


 
Anatoly Podgoretsky ©   (2008-04-23 12:36) [12]

> Arinyshka  (23.04.2008 12:17:00)  [0]

Правильно говорит, код из Вредных Заветов

Создание должно быть до try


 
Ega23 ©   (2008-04-23 12:36) [13]


> Сам попался? :)


С некоторых пор, если есть вероятность того, что в конструкторе raise встретится, предпочитаю сначала nil приравнять...  :)


 
Anatoly Podgoretsky ©   (2008-04-23 12:38) [14]


> Потому что если в конструкторе произойдёт исключение, то
> TempBitmap будет равен nil.

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


 
{RASkov} ©   (2008-04-23 12:42) [15]

> [9] Ega23 ©   (23.04.08 12:30)

А вот такой вариант:
function CrBut: TButton;
begin
 Result:=TButton.Create(nil);
 Result.Tag:=Random(15);
 Result.Caption:=IntToStr(Result.Tag);
 if Result.Tag<7 then begin
  raise Exception.Create("Error in constructor");
  Result.Free;
 end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var B: TButton;
begin
 Randomize;
 B:=CrBut;
 try
  B.Parent:=Self;
  B.Caption:=B.Caption+" Ok";
  ShowMessage("B Ok");
 finally
  B.Free;
  ShowMessage("Finally");
 end;
end;


 
ANB   (2008-04-23 12:44) [16]


> TempBitmap  := TBitmap.Create;
> try
> TempBitmap.LoadFromFile(OpenDialog1.FileName);
> finally
> TempBitmap.Free;
> end;

TempBitmap  := nil;
try
 TempBitmap  := TBitmap.Create;
 TempBitmap.LoadFromFile(OpenDialog1.FileName);
finally
 TempBitmap.Free;
end;

Это классика. Позволяет избежать дублирования финалли, если объектов много, при этом все корректно отработает.


 
{RASkov} ©   (2008-04-23 12:47) [17]

> [9] Ega23 ©   (23.04.08 12:30)
> Button2Click

В этом случае мы попадаем в финал так как коструктор тоже в защитном блоке...


 
Leonid Troyanovsky ©   (2008-04-23 13:12) [18]


> ANB   (23.04.08 12:44) [16]

> Это классика.

Это заблуждение.

Исключения конструктора следует передавать обработчику
следующего уровня.
А защищать ресурсы в этом случае не нужно - деструктор
вызовется автоматом.

--
Regards, LVT.


 
{RASkov} ©   (2008-04-23 13:15) [19]

> [16] ANB   (23.04.08 12:44)
> TempBitmap  := nil;
> try
> TempBitmap  := TBitmap.Create;
> TempBitmap.LoadFromFile(OpenDialog1.FileName);
> finally
> TempBitmap.Free;
> end;
>
> Это классика.

А по мне, мне кажется [1] более роднее и вернее.... [16] и выглядит как-то подозрительно...
А если после возникновения ошибки в конструкторе, он(конструктор) вернет не рыбу не мясо... т.е. не nil и не объект...
Я правда трудно себе это представляю, но.... в финале АВ :)


 
Плохиш ©   (2008-04-23 13:19) [20]


> А если после возникновения ошибки в конструкторе, он(конструктор)
> вернет не рыбу не мясо... т.е. не nil и не объект...

При возникновении исключения в конструкторе, операция присваивания не будет выполнена.


 
{RASkov} ©   (2008-04-23 13:20) [21]

> [20] Плохиш ©   (23.04.08 13:19)
> При возникновении исключения в конструкторе, операция присваивания
> не будет выполнена.

:)
Ну да... тоже верно... Но все равно [1] мне кажется вернее...


 
ANB   (2008-04-23 13:40) [22]

http://softwarer.ru/memory.html

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


 
Palladin ©   (2008-04-23 13:53) [23]

Автор Александр Просторов, всемирно известный классик кодирования. всем пасть ниц

Тема многократного использования идентификатора объекта не раскрыта


 
Arinyshka   (2008-04-23 15:09) [24]

Уффф... ну и дискуссия :)
А вот я еще один объект завожу... освобождаю по form.Close.

unit u;
interface

type
 TSetPayFrm = class(TMGSprForm)
 
var
SetPayFrm  : TSetPayFrm;
ListImage:TStringList;

implementation

procedure TSetPayFrm.InitImageList;
var MyStream: TStream; TempBitmap:TBitmap;
begin

try
ListImage:=TStringList.Create;

except
ListImage.Free;

end;

procedure TSetPayFrm.TbCloseClick(Sender: TObject);
begin
Close;
end;

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

end.

Проблема в том, что он мне нужен и в других юнитах, на протяжении работы приложения. Поэтому в процедурке, создающей его, finaly меня не устраивает.
Но в случае except у меня 2 освобождения... Где я неправа?


 
Рамиль ©   (2008-04-23 15:15) [25]

Не надо загонять в try создание объекта. Если возникла ошибка при его создании, то вызывать деструктор лишено какого либо смысла.


 
Palladin ©   (2008-04-23 15:18) [26]

ListImage:=TStringList.Create; идет на верх над try
в finally пишем FreeAndNil(ListImage) ну или
ListImage.Free;
ListImage:=Nil;

в объявлении Var пишем
ListImage:TStringList=Nil;


 
Восхищенный   (2008-04-23 15:26) [27]

Какая интересная дискуссия. И что интересно - ни одного повтора.


 
Arinyshka   (2008-04-23 15:48) [28]


> ListImage:=TStringList.Create; идет на верх над try
> в finally пишем FreeAndNil(ListImage) ну или
> ListImage.Free;
> ListImage:=Nil;

Подождите... разве я не потеряю значения nil? Я инициализировала и освободила?


 
Arinyshka   (2008-04-23 15:50) [29]

ой, имела в виду список свой.


 
Andy BitOff ©   (2008-04-23 16:09) [30]

В Init в except FreeAndNil(ListImage), а ListImage:=TStringList.Create вынести над try. Далее по коду, если надо обратиться к ListImage делаешь проверку не Nil ли он.


 
ANB   (2008-04-23 16:31) [31]


> Palladin ©   (23.04.08 13:53) [23]
> Автор Александр Просторов, всемирно известный классик кодирования.
>  всем пасть ниц
>
> Тема многократного использования идентификатора объекта
> не раскрыта

На SQL.ru сходи - познакомся.


 
Anatoly Podgoretsky ©   (2008-04-23 16:32) [32]

> Arinyshka  (23.04.2008 15:09:24)  [24]

> Проблема в том, что он мне нужен и в других юнитах, на протяжении работы приложения

В таком случае никаких переменных, переместить в класс, а доступ через контролируемое свойство Gettet/Setter и даже создавать извне не надо, Gettet/Setter с этим сами справятся. Никаких проблем с достоверность указателя не будет, всегда истинное.


 
Loginov Dmitry ©   (2008-04-23 22:43) [33]

http://matrix.kladovka.net.ru/index.php?page=tryfinally


 
Игорь Шевченко ©   (2008-04-23 23:02) [34]

ANB   (23.04.08 13:40) [22]


> Читать сомневающимся до полного просветления.


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


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

ANB   (23.04.08 16:31) [31]

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


 
ANB   (2008-04-24 10:31) [36]

Игорь Шевченко ©   (23.04.08 23:04) [35]

В случае с одним объектом, конечно, доп.строки являются лишними.
Это я по привычке пишу, чтобы потом не переделывать, если в процедуре понядобятся еще объекты.
Однако рассмотрим код :

Obj1  := nil;
Obj2  := nil;
Obj3  := nil;
Obj4  := nil;
Obj5  := nil;
try
 Obj1  := TObj.Create;
 Obj2  := TObj.Create;
 Obj3  := TObj.Create;
 Obj4  := TObj.Create;
 Obj5  := TObj.Create;
 ...
 работа с объектами и куча другого кода
finally
 FreeAndNil(Obj1);
 FreeAndNil(Obj2);
 FreeAndNil(Obj3);
 FreeAndNil(Obj4);
 FreeAndNil(Obj5);
end;

Как без начального зануливания переменных под объекты это написать и корректно и читабельно ?

ЗЫ. Большуюя часть тактов процессора нынче съедают не наши приложения а рисование рюшечек операционки. Да и рюшечек наших приложений частенько тоже.


 
Ega23 ©   (2008-04-24 10:35) [37]


> ANB   (24.04.08 10:31) [36]


Зачем создание внутрь try тащить???


 
ЮЮ ©   (2008-04-24 10:51) [38]

> Зачем создание внутрь try тащить???

Затем, что ошибка может настичь и на Obj5  := TObj.Create; где же тогда освобождать Obj1 &#133 Obj5

P/s/ Нафига только такими объектами пользоваться, которые ломаются уже в конструкторе. :)
В реальной жизни так печься только о TFileStream-e приходилось


 
Ega23 ©   (2008-04-24 10:58) [39]


> Затем, что ошибка может настичь и на Obj5  := TObj.Create;
>  где же тогда освобождать Obj1 … Obj5


А в таком случае надо по-хорошему так:

Obj1 := TObj.Create;
try
 Obj2 := TObj.Create;
 try
   Obj3 := TObj.Create;
   try
      .......
   finally
     Obj3.Free;
   end;
 finally
   Obj2.Free;
 end;
finally
 Obj1.Free;
end;


 
{RASkov} ©   (2008-04-24 10:59) [40]

> [36] ANB   (24.04.08 10:31)
> это написать и корректно и читабельно ?

Obj1  := TObj.Create;
 try
  Obj2  := TObj.Create;
  try
  Obj3  := TObj.Create;
   try
   Obj4  := TObj.Create;
    try
     Obj5  := TObj.Create;
     try
...
работа с объектами и куча другого кода
     finally
      FreeAndNil(Obj5);
     end;
    finally
     FreeAndNil(Obj4);
    end;
   finally
    FreeAndNil(Obj3);
   end;
  finally
   FreeAndNil(Obj2);
  end;
 finally
  FreeAndNil(Obj1);
 end;

или при уверенности, что в конструкторе не будет ошибок, то:
Obj1  := TObj.Create;
Obj2  := TObj.Create;
Obj3  := TObj.Create;
Obj4  := TObj.Create;
Obj5  := TObj.Create;
try
...
работа с объектами и куча другого кода
finally
FreeAndNil(Obj1);
FreeAndNil(Obj2);
FreeAndNil(Obj3);
FreeAndNil(Obj4);
FreeAndNil(Obj5);
end;
Но если честно, то у меня такого в коде никогда еще не встречалось :)



Страницы: 1 2 3 4 5 6 7 8 9 
10 11 12 13 14 15 16 17 вся ветка

Текущий архив: 2008.06.08;
Скачать: CL | DM;

Наверх




Память: 0.58 MB
Время: 0.031 c
2-1210754697
Matveih1
2008-05-14 12:44
2008.06.08
Как узнать загружен пакет или нет


2-1210672414
nelco
2008-05-13 13:53
2008.06.08
Помогите с DBGrid


15-1209127576
foo fighters
2008-04-25 16:46
2008.06.08
как с помощью командной строки узнать объем раздела?


8-1181992036
Michael L Birnov
2007-06-16 15:07
2008.06.08
Прерисовка в канве "моргает"


2-1210918003
Татьяна
2008-05-16 10:06
2008.06.08
Экспорт данных в Excel