سؤال

يرجى النظر في الوظائف الثلاث.

std::string get_a_string()
{
    return "hello";
}

std::string get_a_string1()
{
    return std::string("hello");
}

std::string get_a_string2()
{
    std::string str("hello");
    return str;
}
  1. هل سيتم تطبيق RVO في جميع الحالات الثلاث؟
  2. هل من المقبول إرجاع مؤقت كما في الكود أعلاه؟ أعتقد أنه على ما يرام لأنني أعيدها بالقيمة بدلاً من إرجاع أي إشارة إليها.

أي أفكار؟

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

المحلول

في حالتين أولي ، سيحدث تحسين RVO. RVO هي ميزة قديمة ومعظم المجمعين يدعمها. الحالة الأخيرة تسمى NRVO (اسمه RVO). هذه ميزة جديدة نسبيا من C ++. يسمح Standard ، ولكنه لا يتطلب تنفيذ NRVO (وكذلك RVO) ، لكن بعض المترجمين يدعمونه.

يمكنك قراءة المزيد عن RVO في البند 20 من كتاب Scott Meyers أكثر فعالية C ++. 35 طرق جديدة لتحسين برامجك وتصميماتك.

هنا هي مقالة جيدة عن NRVO في Visual C ++ 2005.

نصائح أخرى

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

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

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

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

بالمناسبة ، فإن إعادة الإشارة أمر ممكن بالطبع كما رأيت في رمز آخر. ما لا يجب عليك فعله هو إرجاع كائن محلي TA المرجعي.

std::string& get_a_string2()
{
    std::string str("hello");
    return str; //error!
}

سوف ينتج خطأ في وقت الترجمة ، كما تعلمون. لكن،

std::string& get_a_string2(std::string& str)
{
    // do something to str
    return str; //OK
}

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

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

  2. نعم ، لا بأس ، على الرغم من أنك لم تذكر أبدًا ما تهتم به ؛ سرعة؟ نمط؟ يمكنك تمديد مؤقت محلي إلى مرجع const - عمر المؤقتة إلى عمر المرجع - جربه وتجربه بنفسك! (Herb Sutter exaplins هذا هنا) انظر نهاية المنشور على سبيل المثال.

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

int foo() { return 42; }

int main(int, char**)
{
    const int &iRef = foo();
    // iRef is valid at this point too!
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top