لماذا تستخدم معظم أمثلة دلفي Fillchar () لتهيئة السجلات؟

StackOverflow https://stackoverflow.com/questions/783825

  •  13-09-2019
  •  | 
  •  

سؤال

تساءلت فقط، لماذا تستخدم معظم أمثلة دلفي Fillchar () لتهيئة السجلات.

type
  TFoo = record
    i: Integer;
    s: string; // not safe in record, better use PChar instead
  end;

const
  EmptyFoo: TFoo = (i: 0; s: '');

procedure Test;
var
  Foo: TFoo;
  s2: string;
begin
  Foo := EmptyFoo; // initialize a record

  // Danger code starts
  FillChar(Foo, SizeOf(Foo), #0);
  s2 := Copy("Leak Test", 1, MaxInt); // The refcount of the string buffer = 1
  Foo.s = s2; // The refcount of s2 = 2
  FillChar(Foo, SizeOf(Foo), #0); // The refcount is expected to be 1, but it is still 2
end;
// After exiting the procedure, the string buffer still has 1 reference. This string buffer is regarded as a memory leak.

هنا (http://stanleyxu2005.blogspot.com/2008/01/potential-memory-Leak-by-initializing.html.) هي ملاحظتي حول هذا الموضوع. IMO، تعلن ثابتا بالقيمة الافتراضية هي طريقة أفضل.

هل كانت مفيدة؟

المحلول

أسباب تاريخية، في الغالب. تعود Fillchar () إلى أيام توربو باسكال واستخدمت لهذه الأغراض. الاسم هو حقا قليلا من سوء القسم لأنه بينما يقول ملءشار()، هو حقا ملءبايت(). السبب هو أن المعلمة الأخيرة يمكن أن تأخذ سحر أو بايت. حتى Fillchar (Foo، Sizeof (Foo)، # 0) و Fillchar (Foo، Sizeof (Foo)، 0) مكافئة. مصدر آخر للارتباك هو أنه اعتبارا من دلفي 2009، لا يزال Fillchar يملأ بايت فقط على الرغم من أن Char يعادل Wideechar. أثناء النظر إلى الاستخدامات الأكثر شيوعا لملء Fillchar من أجل تحديد ما إذا كان معظم الأشخاص يستخدمون Fillchar لملء الذاكرة بالفعل مع بيانات الأحرف أو استخدمه فقط لتهيئة الذاكرة مع بعض القيمة البايتية، وجدنا أنه الحالة الأخيرة التي سيطرت على استخدامها بدلا من السابق. مع ذلك قررنا الحفاظ على المرحلة المركزية لملء البايت.

صحيح أن مسح سجل مع Fillchar الذي يحتوي على حقل معلن باستخدام أحد الأنواع "المدارة" (السلاسل، المتغير، الواجهة، الصفائف الديناميكية) غير آمنة إذا لم يتم استخدامها في السياق المناسب. في المثال الذي قدمته، ومع ذلك، فإنه آمن فعلا استدعاء Fillchar على متغير السجل المعلن محليا طالما أنه أول شيء تقوم به على الإطلاق في السجل في هذا النطاق. وبعد السبب هو أن المحول البرمجي قد أنشأ التعليمات البرمجية لتهيئة حقل السلسلة في السجل. سيؤدي ذلك بالفعل إلى تعيين حقل السلسلة إلى 0 (NIL). استدعاء Fillchar (FOO، Sizeof (FOO)، 0) ستصدر فقط الرقم القياسي بأكمله مع 0 بايت، بما في ذلك حقل السلسلة الموجود بالفعل 0. باستخدام Fillchar على متغير السجل بعد تم تعيين قيمة لحقل السلسلة، لا ينصح. يعد استخدام التقنية الثابتة المهيئة لديك حل جيد للغاية هذه المشكلة لأن المحول البرمجي يمكن أن يولد التعليمات البرمجية الصحيحة لضمان الانتهاء من قيم السجل الموجودة بشكل صحيح أثناء التعيين.

نصائح أخرى

إذا كان لديك دلفي 2009 والإصدارات الأحدث، فاستخدم Default اتصل لتهيئة سجل.

Foo := Default(TFoo); 

يرى إجابة ديفيد للسؤال كيفية وجود سجلات مجانية بشكل صحيح تحتوي على أنواع مختلفة في دلفي مرة واحدة؟.

تعديل:

ميزة استخدام Default(TSomeType) اتصل، هو أنه يتم الانتهاء من السجل قبل مسحها. لا توجد تسرب الذاكرة وعدم وجود مكالمة منخفضة المستوى غير الصريح إلى Fillchar أو Zeromem. عندما تكون السجلات معقدة، ربما تحتوي على سجلات متداخلة وغيرها، يتم إلغاء خطر ارتكاب الأخطاء.

يمكن جعل طريقتك لتهيئة السجلات أكثر بساطة:

const EmptyFoo : TFoo = ();
...
Foo := EmptyFoo; // Initialize Foo

في بعض الأحيان تريد معلمة أن يكون لها قيمة غير افتراضية، ثم تفعل مثل هذا:

const PresetFoo : TFoo = (s : 'Non-Default'); // Only s has a non-default value

سيوفر هذا بعض الكتابة ويتم تعيين التركيز على الأشياء المهمة.

Fillchar على ما يرام للتأكد من أنك لا تحصل على أي القمامة في جديد، غير مهم هيكل (سجل، المخزن المؤقت، Arrray ...).
لا ينبغي أن تستخدم "إعادة تعيين" القيم دون معرفة ما هي إعادة تعيينك.
لا أكثر من مجرد الكتابة MyObject := nil وتوقع تجنب تسرب الذاكرة.
في Particulart، يتم مشاهدة جميع الأنواع المدارة بعناية.
انظر وضع اللمسات الأخيرة على وظيفة.

عندما يكون لديك القدرة على الكمان مباشرة مع الذاكرة، هناك دائما طريقة لإطلاق النار على نفسك في القدم.

Fillchar. يستخدم عادة لملء صفائف أو السجلات مع أنواع الرقمية فقط والمصفيف. أنت تصحيح أنه لا ينبغي أن تستخدم عندما يكون هناك سلاسل (أو أي متغيرات عد المراجعة) في سجل.

على الرغم من اقتراحك باستخدام مقدار ثابت لتهيئة ذلك سيعمل، تأتي مشكلة في اللعب عندما يكون لدي طول متغير مجموعة مصفوفة أنني أريد تهيئة.

قد يسأل السؤال أيضا:

لا يوجد zeromemory. وظيفة في ويندوز. في ملفات الرأس (winbase.h) إنه ماكرو أنه، في العالم C، يتحول حولها والمكالمات ميمزة:

memset(Destination, 0, Length);

Zeromemory هي مصطلح اللغة المحايدة "وظيفة النظام الأساسي الخاص بك التي يمكن استخدامها لذاكرة صفرية"

أي ما يعادل دلفي memset هو FillChar.

نظرا لأن دلفي ليس لديه وحدات ماكرو (وقبل أيام التسخين)، فاتصل zeromemory. يعني أنه كان عليك أن تعاني من عقوبة دعوة وظيفة إضافية قبل أن تصل في الواقع إلى Fillchar..

لذلك في نواح كثيرة، استدعاء Fillchar. هو تحسين الأداء الصغير - الذي لم يعد موجودا الآن zeromemory. ينطوي:

procedure ZeroMemory(Destination: Pointer; Length: NativeUInt); inline;

قراءة القراءة

يحتوي Windows أيضا على sacectoreromemory. وظيفة. يفعل الشيء نفسه بالضبط zeromemory.. وبعد إذا كان يفعل نفس الشيء كما zeromemory., ، لماذا موجود؟

لأن بعض مترجم C / C ++ Smart قد يتعرف على أن إعداد الذاكرة 0 قبل التخلص من الذاكرة مضيعة للوقت - وتحسين المكالمة zeromemory..

لا أعتقد أن مترجم دلفي هو ذكي أكبر عدد ممكن من المحامرة الأخرى؛ لذلك ليس هناك حاجة ل sacefillcar..

تقليديا، شخصية بايت واحدة (لم تعد صحيحة ل Delphi 2009)، لذا فإن استخدام Fillchar مع # 0 سيؤدي إلى تعالى الذاكرة المخصصة بحيث تحتوي فقط على Nulls أو BYTE 0 أو BIN 00000000.

يجب عليك بدلا من ذلك استخدام zeromemory. وظيفة التوافق، والتي لديها نفس معلمات المكالمات مثل Fillchar القديم.

هذا السؤال لديه ضمني أوسع كان في ذهني للأعمار. أنا أيضا، تم طرحه باستخدام Fillchar للسجلات. هذا لطيف لأننا نضيف في كثير من الأحيان حقول جديدة إلى سجل (البيانات) وبالطبع Fillchar (REC، Sizeof (REC)، # 0) يعتني بهذه الحقول الجديدة. إذا فعلنا ذلك بشكل صحيح "، علينا التكرار من خلال جميع مجالات السجل، وبعضها يمكن تعداد أنواعها، والتي قد يسجل بعضها يسجل أنفسهم ويكون الكود الناتج أقل قابلية لقراءة وكذلك خاطئة إذا لم نضيف جديد حقول تسجيلها بجد. حقول السلسلة شائعة، وبالتالي Fillchar ليست الآن الآن. قبل بضعة أشهر، ذهبت وتحولت كل ما عندي من الأمراض على السجلات مع حقول السلسلة إلى المقاصة المكرمة، لكنني لم أكن سعيدا بالحل وتتساءل عما إذا كانت هناك طريقة أنيقة للقيام "ملء" على أنواع ببساطة (ترتيبي / تعويم) و "وضع اللمسات الأخيرة" على المتغيرات والسلاسل؟

إليك طريقة أفضل لتهيئة الأشياء دون استخدام Fillchar:

سجل في السجل (لا يمكن تهيئة)
كيفية تهيئة صفيف ثابت؟

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top