ورود

View Full Version : خالی کردن متغییرها



mohsen_r
یک شنبه 25 آذر 1386, 11:35 صبح
من چطور میتونم متغییرها ومقدار گرفته شده دکمه را خالی کنم به صورت یکجا نه بصورت تک به تک داخل یک فرم لطفا راهنمایی کنید

Delphi Coder
یک شنبه 25 آذر 1386, 11:42 صبح
خالی کردن متغییر معنی نمیده.
فکر میکنم کل فرم رو Free کنید بعد دوباره Create کنید بهتره.

A.Nemati
یک شنبه 25 آذر 1386, 11:59 صبح
متغیرها اگر از نوع آبجکت باشن، باید با Free آنها را آزاد کنید و اگر غیر از این باشند (مثل انواع داده‌های استاندارد و رکوردها)، با خارج شدن از محدوده تعریفشون، آزاد می‌شن.
اگر شما در رویداد کلیک یک دکمه تعدادی متغیر استاندارد (مثل integer, bolean , ...) گرفته باشید، کامپایلر وقتی به انتهای این رویداد می‌رسه و می‌خواهد از اون خارج بشه، بطور اتوماتیک خودش این متغیرها را آزاد می‌کنه اما اگه از متغیرهای آبجکتی (مثل TStringList) استفاده کردید، باید قبل از خروج، آنرا آزاد کنید. روش استاندارد، استفاده از بلوک try finally است:


...
var
sl: TStringList;
...
begin
...
sl:= TStringList.Create;
try
....// Use sl here
finally
sl.Free;
end;
...
end;

rasool_brn
یک شنبه 25 آذر 1386, 16:45 عصر
تمامی اجزا ساخت یعنی شی هر کلاسی که از کلاس TCompunent مشتق می شه در زمان ایجاد یه پارامتر از نوع TComponent دریافت می کنه که به عنوان مالک شی در نظر گرفته می شه.
Button1:=TButton.Create(AOwner: TComponent)این مالک وظیفه آزاد کردن حافظه شی رو بر عهده داره. وقتی که جزئی رو مثل یه Button روی form می زارین خود دلفی Form رو به عنوان مالک شی Button در نظر می گیری در این صورت حافظه شی Button با بستن form به صورت خودکار آزاد می شه. برای اجزاء ساختی که خودتون در زمان اجرا ایجاد می کنین هم به همین صورته با این تفاوت که خودتون می تونین مالک جزء رو تعیین کنین(مثلا یه Button رو مالک تمام اجزایی که خودتون ایجاد می کنین قرار بدین در این حالت اگه حافظه مربوط به Button رو آزاد کنین تمام اجزاء آزاد می شن ).
در مورد شی کلاسهایی که از TComponent مشتق نمی شن باید اونارو خودتون تک تک آزاد کنین و البته نه با متد Free . متد Free فقط حافظه مربوط به شی رو آزاد می کنه ولی nil رو به شی تخصیص نمی ده , بهتره که بعد از استفاده از متد Free مقدار nil رو به شی تخصیص بدین و بهتره از اون اینه که از تابع FreeAndNil به جای دو دستور بالا استفاده کنین.در مورد بلوک Try/Finally هم بگم که می تونین با استفاده از بلوک Try/finally آزاد شدن حافظه شی هارو تضمین کنین ولی به هر حال بازم بایددر قسمت Finally شی هارو تک تک آزاد کنین.

A.Nemati
یک شنبه 25 آذر 1386, 17:13 عصر
متد Free فقط حافظه مربوط به شی رو آزاد می کنه ولی nil رو به شی تخصیص نمی ده , بهتره که بعد از استفاده از متد Free مقدار nil رو به شی تخصیص بدین.

nill کردن یک شی فقط وقتی کاربرد داره که شما بخواهید مقدار داشتن و معتبر بودن شی را چک کنید:


if Assigned(sl) then
...

در غیر اینصورت ضرورتی ندارد که هیچ، کامپایلر هم یک Hint به شما می‌دهد که مقدار تخصیص داده شده در هیچ‌کجا استفاده نشده است و یک تخصیص بی‌مورد انجام شده است.

Cave_Man
یک شنبه 25 آذر 1386, 17:29 عصر
این مالک وظیفه آزاد کردن حافظه شی رو بر عهده داره. وقتی که جزئی رو مثل یه Button روی form می زارین خود دلفی Form رو به عنوان مالک شی Button در نظر می گیری در این صورت حافظه شی Button با بستن form به صورت خودکار آزاد می شه

با بستن فرم نه با Release کردن فرم

rasool_brn
یک شنبه 25 آذر 1386, 21:36 عصر
اگرمتد free مربوط به شی رو فرا خوانی کنین شی موجود در حافظه از بین میره ولی هنوز متغیر شی به مکانی از حافظه ارجاع داره . بنابراین اگر متد free رو دوباره فراخوانی کنین چون متغیر شی به جایی اشاره می کنه که هیچ شیئی وجود نداره برنامه دچار خطا می شه.چیزی که شما می گین در صورتی درسته که که در برنامه از یک کد پیوسته (مثل کدی که شما نوشتین)استفاده بشه یعنی در یک بلاک شی ایجاد بشه , کارهایی روش انجام بشه و بعد هم شی آزاد بشه . به هر حال تخصیص nil به شی بعد از فراخوانی free یه عادت خوب در برنامه نویسیه حتی اگه یه تخصیص بی مورد باشه .

با بستن فرم نه با Release کردن فرمیعنی چی ؟

Cave_Man
یک شنبه 25 آذر 1386, 23:14 عصر
یعنی چی ؟

با بستن فرم آبجکتهای روی اون آزاد نمیشن بلکه با Release کردن این اتفاق میفته که به اشتباه گفتید

rasool_brn
دوشنبه 26 آذر 1386, 00:22 صبح
با بستن فرم آبجکتهای روی اون آزاد نمیشن بلکه با Release کردن این اتفاق میفته که به اشتباه گفتید وقتی متد close فرم فراخوانی بشه یا دکمه close زده بشه(به طور خلاصه فرم بسته بشه) توابع و رویدادهای زیر به ترتیب فراخوانی می شن:
رویدادهای تخریب فرم
1_CloseQuery
OnCloseQuery_2
Close_3
OnClose_4
BeforeDestruction_5(از دید پنهان است)این متد رویداد OnDestroy را فرا می خواند
6_OnDestroy
Destructor_7فرم (از دید شما پنهان است)Destroy

مرحله 7 باعث می شه که شی form تخریب بشه و طبعا حافظه تمام اشیاء روی فرم هم آزاد می شه.

vcldeveloper
دوشنبه 26 آذر 1386, 01:17 صبح
وقتی متد close فرم فراخوانی بشه یا دکمه close زده بشه(به طور خلاصه فرم بسته بشه) توابع و رویدادهای زیر به ترتیب فراخوانی می شن:خیر. بستن فرم باعث آزاد شدن حافظه اختصاص داده شده به آن نمیشه. اگر اینطور بود، باید بعد از بستن فرم، برای نمایش مجدد آن، دوباره آن را Create می کردید. البته در صورت نسبت دادن مقدار caFree به پارامتر Action در رویداد OnClose یک فرم، میشه آن فرم را در زمان بسته شدن Free کرد.

بستن فرم اصلی پروژه باعث Free شدن آن و اجرای متد Application.Terminate میشه که باعث خروج از برنامه و آزاد شدن کل منابع اختصاص داده شده به آن میشه.

JAFO_IRAN
دوشنبه 26 آذر 1386, 06:25 صبح
سلام

ضمن تایید کامل صحبت‌های قبلی و تقریبا به عنوان نکته جنبی:

1. احتمالا منظور از Release، اشاره به این نکته بودن که بستن فرم لزوما منجر به آزاد شدن نمیشود که در پست‌های قبلی به درستی اشاره شد. پس در context این بحث، Release با Free تفاوتی ندارند. اما این‌ها دو متد از TCustomForm هستند - Release عملا یک Message برای Free شدن در Queu قرار میده؛ پس عمل آزاد شدن پس از به سرانجام رسیدن بقیه Messageها انجام میشه (عملا آسنکرون) و این باعث میشه که بتونیم از Release در Event Handlerهای داخل فرم استفاده کنیم - تصور کنید که از داخل یکی از متدهای فرم بخواهیم فرم را آزاد کنیم؛ اجرای مستقیم Free کارساز نخواهد بود.

2. داریم در مورد Win32 صحبت میکنیم (خیلی جالبه که این نکته برای بقیه هم مثل من پیش‌فرض شده - احساس خوبیه)

ارادت

A.Nemati
دوشنبه 26 آذر 1386, 11:05 صبح
به هر حال تخصیص nil به شی بعد از فراخوانی free یه عادت خوب در برنامه نویسیه حتی اگه یه تخصیص بی مورد باشه


من هم قبلا اینطور فکر می‌کردم ولی واقعیت مسئله این است که یکی از بهترین راهنماها جهت استاندارد کردن کد ما، همان Hint‌ها و Warningهای کامپایلر است.
وقتی یک Hint به شما داده می‌شود، یعنی کد شما بهینه نیست و شما هنوز به استاندارد نرسیده‌اید، تخصیص حافظه بی‌مورد، مقدار دهی بی‌مورد، تعریف متغیرهای بدون کاربرد و ... مسائلی هستند که گرچه ممکن است برای برنامه ما خطرناک نباشد، اما باعث می‌شوند که ما از یک کد استاندارد بی‌بهره بمانیم.
شخصا اعتقاد دارم که اگر بتوانیم استانداردها را رعایت کنیم، برنامه کاملتری را ارایه داده‌ایم. چه بسا همین رعایت نکردن استانداردها باعث می‌شوند که به روش‌هایی عادت کنیم که پس از مدتی این استاندارد شخصی، برای ما یک حکم استاندارد و روش صحیح را داشته باشد و گاهی همین‌ها باعث شوند که در سیستم‌هایی مانند سیستم‌های سازمانی و بزرگ یا سیستم‌هایی که پیچیدگی‌های خاصی دارند، با خطاهایی برخورد کنیم(مخصوصا در محیط مشتری) که مدتها وقت و انرژی صرف حل آنها کنیم و دست آخر برای حل آنها دست به ترفندهای عجیب‌تری بزنیم!
این ریزه‌کاری‌ها را دست کم نگیرید.

vcldeveloper
دوشنبه 26 آذر 1386, 11:32 صبح
من هم قبلا اینطور فکر می‌کردم ولی واقعیت مسئله این است که یکی از بهترین راهنماها جهت استاندارد کردن کد ما، همان Hint‌ها و Warningهای کامپایلر است.
Nil کردن یک اشاره گر از هر نوعی وقتی باهاش کاری نداریم، کار درستی هست. اگه شما بعد از Nil کردن یک متغیر از کامپایلر هشدار میگیرید، در نحوه تعریف و کار کردن با آن متغیر اشتباهی انجام دادید، وگرنه در شرایط عادی کامپایلر برای Nil کردن یک شی آزاد شده هشدار یا Hint ایی نمیده.
در ضمن، در SysUtils برای راحتتر شدن کار، تابع FreeAndNil معرفی شده که خودش بالافاصله پس از Free کردن شی، آن را Nil میکنه و در صورت استفاده از آن، نیازی به نوشتن کد برای Nil کردن نیست.
این نکته را هم بگم که بعضی Type ها را باید فقط Nil کرد، چون مدیریت حافظه اختصاص داده شده به آنها را دلفی خودش برعهده می گیرد، مثل: string, Dynamic Array و Interface.

A.Nemati
دوشنبه 26 آذر 1386, 11:54 صبح
nill کردن یک شی فقط وقتی کاربرد داره که شما بخواهید مقدار داشتن و معتبر بودن شی را چک کنید

کاملترش اینه: وقتی کاربرد داره که شما بخواهید در ادامه کار بهش رجوع کنید.


Nil کردن یک اشاره گر از هر نوعی وقتی باهاش کاری نداریم، کار درستی هست. اگه شما بعد از Nil کردن یک متغیر از کامپایلر هشدار میگیرید، در نحوه تعریف و کار کردن با آن متغیر اشتباهی انجام دادید، وگرنه در شرایط عادی کامپایلر برای Nil کردن یک شی آزاد شده هشدار یا Hint ایی نمیده.


به نظر شما کد زیر ایراد داره؟

procedure TForm1.Button1Click(Sender: TObject);
var
sl: TStringList;
begin
sl:= TStringList.Create;
try
sl.Append(Self.Caption);
ShowMessage(sl.Strings[0]);
finally
sl.Free;
sl:= nil;
end;
end;
ظاهرا چیزی نیست ولی کامپایلر می‌گه

[Hint] Unit1.pas(278): Value assigned to 'sl' never used
که البته داره به خط sl:= nil اشاره می‌کنه.

خب به نظر شما دلیل این Hint چیه؟

vcldeveloper
سه شنبه 27 آذر 1386, 02:50 صبح
خب به نظر شما دلیل این Hint چیه؟دلیلش اینه که اصلا nil کردن در آن بخش از کد اثری نداره. در کد بالا، بالافاصله بعد از اجرای خط sl := nil (البته کامپایلر دلفی اونقدر هوشمند هست که این خط رو کامپایل نکنه)، رویه مربوطه تمام میشه. sl هم بصورت local تعریف شده و با پایان یافتن کد رویه بطور خودکار از بین میره.
پس، nil کردن یک متغیر local در پایان تابعی که حوزه تعریف آن متغیر را تعیین می کند، کار بی ارزشی هست و کد مربوطه اصلا توسط دلفی کامپایل نمیشه!
در اینجا کد شما مشمول این بخش از صحبت من میشه:

در نحوه تعریف و کار کردن با آن متغیر اشتباهی انجام دادید