سؤال

أي مما يلي أفضل ولماذا؟(خاصة بـ c++)

أ.

int i(0), iMax(vec.length());//vec is a container, say std::vector
for(;i < iMax; ++i)
{
  //loop body
}

ب.

for( int i(0);i < vec.length(); ++i)
{
  //loop body
}

لقد رأيت نصيحة لـ (أ) بسبب وظيفة الاتصال بطول المدة.هذا يزعجني.ألا يقوم أي مترجم حديث بتحسين (ب) ليكون مشابهًا لـ (أ)؟

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

المحلول

مثال (ب) له معنى مختلف لالمثال (أ)، والمترجم يجب أن تفسر على أنها تكتب عليه.

إذا، (لسبب مختلقة لا أستطيع أن أفكر في)، كتبت رمز للقيام بذلك:

for( int i(0);i < vec.length(); ++i)
{
    if(i%4 == 0)
       vec.push_back(Widget());
}

وأنا حقا لم أكن أريد المترجم لتحسين من كل استدعاء vec.length ()، لأنني سوف تحصل على نتائج مختلفة.

نصائح أخرى

وأنا أحب:

for (int i = 0, e = vec.length(); i != e; ++i)

وبطبيعة الحال، فإن هذا أيضا العمل من أجل المكررات:

for (vector<int>::const_iterator i = v.begin(), e = v.end(); i != e; ++i)

وأنا أحب ذلك لأنه على حد سواء كفاءة (الدعوة end() مرة واحدة فقط)، وأيضا مقتضبة نسبيا (فقط الحاجة إلى كتابة vector<int>::const_iterator مرة واحدة).

أنا مندهش من أن أحدا لم يقل ما هو واضح:

في 99.99% من الحالات، لا يهم.

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

هناك مسألتان للنقاش هنا:

  1. النطاق المتغير
  2. إعادة تقييم الحالة النهائية

نطاق متغير

عادةً، لن تحتاج إلى أن يكون متغير الحلقة مرئيًا خارج الحلقة.لهذا السبب يمكنك إعلان ذلك داخل for بناء.

إعادة تقييم الحالة النهائية

صرح أندرو شيبرد بذلك بشكل جيد:يعني شيئًا مختلفًا لوضع استدعاء دالة داخل الشرط النهائي:

for( vector<...>::size_type i = 0; i < v.size(); ++i ) { // vector size may grow.
   if( ... ) v.push_back( i ); // contrived, but possible
}

// note: this code may be replaced by a std::for_each construct, the previous can't.
for( vector<...>::size_type i = 0, elements = v.size(); i != elements; ++i ) {
}

وماذا هو bodering لك؟ تلك بديلين لا أرى أن تفعل الشيء نفسه. واحد يقوم به عدد محدد من التكرارات، في حين أن البعض يعتمد على الجسم الحلقات.

وثمة بديل آخر colud يكون

for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
 //loop body
}

وإلا إذا كنت بحاجة إلى متغير حلقة خارج الحلقة، والنهج الثاني هو الأفضل.

والمكررات سوف تعطي في الواقع كنت جيدة أو أفضل أداء. (كان هناك موضوع المقارنة كبير على comp.lang.c ++. أدار قبل بضع سنوات).

وبالإضافة إلى ذلك، وأود أن استخدام

int i = 0;

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

لا علاقة لها إلى حد ما:

تحذير:مقارنة بين عدد صحيح موقعة وغير موقعة.

النوع الصحيح لمؤشرات المصفوفة والمتجهات هو size_t.

بشكل صارم التحدث، في C++ هو حتى std::vector<>::size_type.

من المثير للدهشة عدد مطوري C/C++ الذين ما زالوا يخطئون في هذا الأمر.

ودعونا نرى على الشفرة التي تم إنشاؤها (I استخدام MSVS 2008 مع التحسين الكامل).

أ.

int i(0), iMax(vec.size());//vec is a container, say std::vector
for(;i < iMax; ++i)
{
  //loop body
}

وولحلقة تنتج 2 تعليمات المجمع.

ب.

for( int i(0);i < vec.size(); ++i)
{
  //loop body
}

وولحلقة تنتج 8 تعليمات المجمع. vec.size () وinlined بنجاح.

وج.

for (std::vector<int>::const_iterator i = vec.begin(), e = vec.end(); i != e; ++i)
{
  //loop body
}

وولحلقة تنتج 15 تعليمات المجمع (وinlined كل شيء، ولكن رمز لديها الكثير من القفزات)

وهكذا، إذا كان التطبيق الخاص بك هو أداء الاستخدامات الحرجة أ). إلا ب) أو (ج)).

وتجدر الإشارة إلى أن الأمثلة مكرر:

for (vector<T>::iterator it=vec.begin();it!=vec.end();it++){
 //loop body
}

ويمكن أن يبطل مكرر حلقة "انه" يجب على هيئة حلقة يسبب متجه إلى إعادة تخصيص. وبالتالي فإنه لا يعادل

for (int i=0;i<vec.size();++i){
 //loop body
}

وحيث يضيف الجسم حلقة العناصر إلى مركزنا.

والسؤال بسيط: هل بتعديل vec في حلقة

والإجابة على هذا السؤال سوف يؤدي إلى إجابتك أيضا.

وJRH

ومن الصعب جدا للمترجم لرفع دعوة vec.length() في المعرفة الآمنة أنه مستمر، ما لم يحصل inlined ذلك (والتي نأمل في كثير من الأحيان سوف!). ولكن على الأقل i يجب بالتأكيد أن أعلن في النمط الثاني "ب"، حتى إذا تحتاج الدعوة length أن يكون "يدويا" رفع للخروج من حلقة!

هذا هو الأفضل:

typedef vector<int> container; // not really required,
                               // you could just use vector<int> in for loop

for (container::const_iterator i = v.begin(); i != v.end(); ++i)
{
    // do something with (*i)
}
  • أستطيع أن أقول على الفور أنه لا يتم تحديث المتجه
  • يمكن لأي شخص معرفة ما يحدث هنا
  • أنا أعرف كم عدد الحلقات
  • v.end() إرجاع المؤشر واحد الماضي العنصر الأخير حتى لا يكون هناك تكاليف من الحجم
  • سهل التحديث لمختلف الحاويات أو أنواع القيمة

و(ب) لن حساب / استدعاء الدالة في كل مرة.

- تبدأ مقتطفات ----

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

و--- نهاية مقتطفات -

وعن تحسينات لدول مجلس التعاون الخليجي:

https://www.in.redhat.com/software /gnupro/technical/gnupro_gcc.php3

scroll top