Главная страница
    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.055 c
3-1199497352
DimonS
2008-01-05 04:42
2008.06.08
Хитрый отчет в FastReport


2-1209976099
Aleksei
2008-05-05 12:28
2008.06.08
Проверка нового файла на ФТП


2-1210834088
big
2008-05-15 10:48
2008.06.08
Как в StringGrid e удалить выделенную строку?


2-1210856525
Гена_88
2008-05-15 17:02
2008.06.08
SQL in Delphi


2-1210770613
OLGA
2008-05-14 17:10
2008.06.08
Как отсоеденить сотую часть!!!!!!!!





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский