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

Вниз

Освобождение ресурса в 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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.05 c
4-1190441616
antoxa2005
2007-09-22 10:13
2008.06.08
Открыть порт в Брэндмауэре WinXP SP2


15-1209283131
Knight
2008-04-27 11:58
2008.06.08
Флешка взбунтовалась&amp;#133


2-1210671008
Виктор
2008-05-13 13:30
2008.06.08
Помогите найти ошибку в коде


11-1181491706
Robt
2007-06-10 20:08
2008.06.08
ListBox


2-1210787964
Rustam01
2008-05-14 21:59
2008.06.08
курсор в 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
Английский Французский Немецкий Итальянский Португальский Русский Испанский