سؤال

هذا السؤال لديه بالفعل إجابة هنا:

في مكتبة STL، تحتوي بعض الحاويات على مكررات ومن الشائع أنها طريقة ممتازة للتكرار عبر هذه الحاويات بدلاً من كونها حلقات بسيطة على سبيل المثال.

for ( int i=0; i < vecVector.size(); i++ )
{

..

}

هل يمكن لأحد أن يخبرني لماذا وفي أي الحالات يجب علي استخدام التكرارات وفي أي الحالات يجب أن يكون مقتطف الكود أعلاه من فضلك؟

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

المحلول

لاحظ أن تطبيق المتجه عادةً لن يستخدم "int" كنوع الفهرس/الحجم.لذا فإن الكود الخاص بك سوف يثير على الأقل تحذيرات المترجم.

الشمولية

تعمل التكرارات على زيادة شمولية التعليمات البرمجية الخاصة بك.

على سبيل المثال:

typedef std::vector<int> Container ;

void doSomething(Container & p_aC)
{
    for(Container::iterator it = p_aC.begin(), itEnd = p_aC.end(); it != itEnd; ++it)
    {
       int & i = *it ; // i is now a reference to the value iterated
       // do something with "i"
    }
}

الآن، لنتخيل أنك قمت بتغيير المتجه إلى قائمة (لأن القائمة أصبحت الآن أفضل في حالتك).ما عليك سوى تغيير تعريف typedef وإعادة ترجمة التعليمات البرمجية.

إذا كنت قد استخدمت التعليمات البرمجية المستندة إلى الفهرس بدلاً من ذلك، فستحتاج إلى إعادة كتابتها.

وصول

يجب أن يُنظر إلى المُكرِّر كنوع من المؤشر الفائق.إنه "يشير" إلى القيمة (أو، في حالة الخرائط، إلى زوج المفتاح/القيمة).

ولكن لديها طرق للانتقال إلى العنصر التالي في الحاوية.أو السابق.توفر بعض الحاويات إمكانية الوصول العشوائي (المتجه وdeque).

الخوارزميات

تعمل معظم خوارزميات STL على التكرارات أو على نطاقات من التكرارات (مرة أخرى، بسبب الشمولية).لن تتمكن من استخدام الفهرس هنا.

نصائح أخرى

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

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

لذا، ما لم تكن متأكدًا من أن الوصول العشوائي إلى حاويتك رخيص، فاستخدم المكرِّر.

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

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

template <typename InputIterator, typename OutputIterator>
void AddOne(InputIterator begin, InputIterator end, OutputIterator dest)
{
    while (begin != end)
    {
        *dest = *begin + 1;
        ++dest;
        ++begin;
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    vector<int> data;
    data.push_back(1);
    data.push_back(2);
    data.push_back(3);

    // Compute intermediate results vector and dump to console
    vector<int> results;
    AddOne(data.begin(), data.end(), back_inserter(results));
    copy(results.begin(), results.end(), ostream_iterator<int>(cout, " "));
    cout << endl;

    // Compute results and send directly to console, no intermediate vector required
    AddOne(data.begin(), data.end(), ostream_iterator<int>(cout, " "));
    cout << endl;

    return 0;
}

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

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

تتيح لك أدوات التكرار إنشاء قوالب وظائف لا تحتاج إلى معرفة نوع الحاوية التي تعمل عليها.يمكنك أيضًا القيام بما يلي:

#include <algorithm>

void printvalue(double s)
{
    // Do something with s
}

int _tmain(int argc, _TCHAR* argv[])
{
    double s[20] = {0};

    std::for_each(s, s+20, printvalue);

    return 0;
}

وذلك لأن المؤشر القياسي هو أيضًا مكرر صالح لـ for_each.

ديف

المكرر هو في الغالب مستوى أعلى من التجريد.

يفترض مقتطفك أنه يمكن فهرسة الحاوية.هذا صحيح ل std::vector<> وبعض الحاويات الأخرى، على سبيل المثال المصفوفات الخام.

لكن std::set<> يفتقر إلى الفهرسة بشكل كامل ومشغل الفهرس std::map<> سيتم إدراج أي وسيطة يتم توفيرها لها في الخريطة - وليس السلوك المتوقع في ملفك for-حلقة.

كما أن مشكلات الأداء هي مشكلات فقط عندما يتم قياسها وإثبات ذلك.

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