سؤال

إذا حددنا وظيفة عضو داخل تعريف الفئة نفسه ، فهل تعامل بالضرورة مضمّنة أم أنها مجرد طلب للمترجم الذي يمكن أن يتجاهله.

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

المحلول

نعم ، الوظائف التي يتم تعريفها داخل جسم فئة هي ضمنية inline.

(كما هو الحال مع الوظائف الأخرى المعلنة inline هذا لا يعني أن الشكوى يجب أن تؤدي التوسع المضمّن في الأماكن التي يتم فيها استدعاء الوظيفة ، فهي تتيح فقط الاسترخاء المسموح به لـ "قاعدة تعريف واحدة" ، إلى جانب متطلبات إدراج تعريف في جميع وحدات الترجمة حيث يتم استخدام الوظيفة.)

نصائح أخرى

كما ذكر الآخرون ، يتم طلب طريقة محددة داخل الفصل تلقائيًا. من المفيد فهم السبب.

لنفترض أنه لم يكن كذلك. يجب عليك إنشاء رمز لمثل هذه الوظيفة ، وفي كل مكان يطلق عليه ، سيتعين على تعليمات القفزة الفرعية الرجوع إلى الموقع ، عبر الرابط.

class A {
public:
  void f() { ... your code ... }
};

في كل مرة يتم فيها رؤية هذا الرمز ، إذا لم يكن مضمّنًا ، يمكن للمترجم أن يفترض فقط أنه يجب إنشاءه ، لذلك سيولد رمزًا. لنفترض أنه كان هكذا:

A__F_V:

إذا كان هذا الرمز عالميًا ، فإذا صادف أن تتضمن رمز الفئة هذا عدة مرات في وحدات مختلفة ، فسيكون لديك خطأ رمز محدد في وقت الارتباط. لذلك لا يمكن أن يكون عالميا. بدلاً من ذلك ، إنه ملف محلي.

تخيل أنك تتضمن ملف الرأس أعلاه في عدد من الوحدات النمطية. في كل واحد ، ستقوم بإنشاء نسخة محلية من هذا الرمز. أيهما أفضل من عدم التجميع على الإطلاق ، لكنك تحصل على نسخ متعددة من الكود عندما تحتاج حقًا إلى نسخة واحدة فقط.

هذا يقود الاستنتاج التالي: إذا لم يكن المترجم الخاص بك لا يدخل وظيفة ، فأنت أفضل بكثير من إعلانها في مكان ما مرة واحدة ، ولا تطلب أن تكون محدودة.

لسوء الحظ ، ما هو وما هو غير محمول. يتم تعريفه من قبل كاتب التحويل البرمجي. هناك قاعدة جيدة تتمثل في جعل كل بطانة ، لا سيما جميع الوظائف التي تسميها فقط وظيفة ، مضمّنة ، أثناء إزالة النفقات العامة. من المؤكد أن أي شيء أقل من ثلاثة أسطر من التعليمات البرمجية الخطية على ما يرام. ولكن إذا كان لديك حلقة في الكود ، فإن السؤال هو ما إذا كان المترجم سيسمح له بالمضمّن ، وأكثر من ذلك ، إلى أي مدى سترى الفائدة حتى لو فعلت ما تريد.

النظر في هذا الرمز المضمّن:

inline int add(int a, int b) { return a + b; }

إنها ليست صغيرة تقريبًا مثلما سيكون النموذج الأولي في رمز المصدر ، ولكن لغة التجميع التي تم إنشاؤها بواسطة الرمز المضمن أصغر من الدعوة إلى الروتين. لذلك هذا الرمز أصغر وأسرع.

وإذا كنت تمر في الثوابت:

int c= add(5,4);

يتم حلها في وقت الترجمة وليس هناك رمز.

في دول مجلس التعاون الخليجي ، لاحظت مؤخرًا أنه حتى لو لم أقم بمضمنة الكود ، إذا كان محليًا في ملف ، فسيتم ضمها بشكل متسلل على أي حال. فقط إذا أعلنت الوظيفة في وحدة مصدر منفصلة أنها لا تحسن المكالمة.

على الطرف الآخر من الطيف ، لنفترض أنك تطلب خطًا على قطعة 1000 من الكود. حتى إذا كان المترجم الخاص بك سخيفًا بما يكفي لمواكبة ذلك ، فإن الشيء الوحيد الذي تحفظه هو المكالمة نفسها ، والتكلفة هي أنه في كل مرة تسميها ، يجب على المترجم لصق كل هذا الرمز. ، ينمو التعليمات البرمجية الخاصة بك بحجم الروتين * n. لذلك لا يستحق أي شيء أكبر من 10 خطوط إلى حد كبير التحضير ، باستثناء الحالة الخاصة التي يطلق عليها فقط عددًا صغيرًا جدًا من المرات. مثال على ذلك قد يكون في طريقة خاصة يطلق عليها فقط 2 آخرين.

إذا طلبت أن تضمن طريقة تحتوي على حلقة ، فمن المنطقي فقط إذا كانت غالبًا ما تنفذ عددًا صغيرًا من المرات. لكن النظر في حلقة تكرر مليون مرة. حتى لو تم توضيح الرمز ، فإن النسبة المئوية للوقت الذي تقضيه في المكالمة صغيرة. لذا ، إذا كان لديك أساليب مع حلقات فيه ، والتي تميل إلى أن تكون أكبر على أي حال ، فإن هذه تستحق الإزالة من ملف الرأس لأنها أ) تميل إلى رفضها على أنها مضمّنة من قبل المترجم و B) حتى لو كانت مضطربة بشكل عام ، تكون عمومًا لن توفر أي فائدة

يتم التعامل معها بالضرورة من قبل المترجم كطلب مضمّن - وهو ما يمكن أن يتجاهله. هناك بعض التعبيرات لتحديد بعض الوظائف في الرأس (مثل المدمرين الافتراضيين الفارغين) وبعض تعريفات الرأس اللازمة (وظائف القالب) ، ولكن بخلاف ذلك انظر GOTW #33 للمزيد من المعلومات.

لقد لاحظ البعض أن المترجم قد يجوز حتى للمضمّن الوظائف التي لم تطلبها أبدًا ، لكنني لست متأكدًا مما إذا كان ذلك سيهزم الغرض من طلب دخول الوظيفة.

إنه مضمون بالفعل - ولكن يمكن تجاهل أي طلب مضمّن من قبل المترجم.

إنه طلب للمترجم يمكن أن يتجاهله.

يقول معيار ISO C ++ 2003

7.1.2/2 إعلان الوظيفة (8.3.5 ، 9.3 ، 11.4) مع محدد محدد مضمّن يعلن وظيفة مضمّنة. يشير المحدد المضمّن إلى التنفيذ أن الاستبدال المضمّن لجسم الوظيفة عند نقطة الاتصال يجب أن يكون مفضلاً لمكالمة الوظيفة المعتادة
آلية. التنفيذ غير مطلوب لأداء هذا مضمّن
الاستبدال عند نقطة الاتصال ؛ ومع ذلك ، حتى لو كان هذا مضمراً
تم حذف الاستبدال ، ولا تزال القواعد الأخرى للوظائف المضمّنة المحددة بواسطة 7.1.2 محترمة.

7.1.2/3 وظيفة محددة في تعريف الفئة هي خط مضمّن
وظيفة. يجب ألا يظهر المحدد المضمون في إعلان وظيفة نطاق الكتلة.

7.1.2/4 يتم تحديد وظيفة مضمنة في كل وحدة ترجمة في
الذي يتم استخدامه ويجب أن يكون له نفس التعريف بالضبط في كل
حالة (3.2). [ملاحظة: يمكن مواجهة مكالمة إلى الوظيفة المضمنة
قبل ظهور defi-nition في وحدة الترجمة. ] إذا تم الإعلان عن وظيفة ذات ارتباط خارجي مضمّن في وحدة Transla-Tion ، فيجب الإعلان عن ذلك في جميع وحدات الترجمة التي تظهر فيها ؛ لا يلزم التشخيص. يجب أن يكون للدالة المضمنة مع الارتباط الخارجي نفس العنوان في جميع وحدات الترجمة. متغير محلي ثابت في خط خارجي مضمّن
تشير الوظيفة دائمًا إلى نفس الكائن. سلسلة حرفية في
وظيفة الخط الخارجي المضمّن هي نفس الكائن في ترجمة مختلفة
الوحدات.

هناك شيئان لا ينبغي تجميعهما معًا:

  1. كيف تضع علامة على وظيفة على أنها مضمّنة: حددها مع الخط أمام التوقيع أو تحديدها عند نقطة الإعلان ؛
  2. ما سيتعامل مع المترجم مثل هذا العلامات المضمّنة: بغض النظر عن كيفية تمييز الوظيفة على أنها مضمّنة ، سيتم التعامل معها كطلب من المترجم.
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top