سؤال

يرجى النظر في الرمز التالي ،

struct foo
{
    foo()
    {
        std::cout << "Constructing!" << std::endl;
    }

    foo(const foo& f)
    {
        std::cout << "Copy constructing!" << std::endl;
    }

    ~foo()
    {
        std::cout << "Destructing.." << std::endl;
    }
};

foo get()
{
    foo f;
    return f;
}

int main()
{
    const foo& f = get();
    std::cout << "before return" << std::endl;
    return 0;
}

الإخراج على MSVC

Constructing!
Copy constructing!
Destructing..
before return
Destructing..

إخراج مجلس التعاون الخليجي

Constructing!
before return
Destructing..

النتيجة التي تأتي على MSVC تبدو غير صحيحة.

أسئلة

  1. AFAIK ، GCC تنتج النتيجة الصحيحة هنا. لماذا تعطي MSVC نتائج مختلفة ولماذا تقوم ببناء النسخ؟
  2. const foo& f = get() و const foo f = get() ينتج نفس الإخراج بسبب تحسين قيمة الإرجاع. في هذه الحالة ، ما هي طريقة الكتابة التي ينبغي تفضيلها؟

أي أفكار..

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

المحلول

بناء MSVC الخاص بك ليس له تحسينات على. قم بتشغيلها ، ستحصل على إخراج متطابق لكليهما.

تعمل GCC فقط ، بشكل افتراضي ، RVO على مؤقتك. إنه يفعل بشكل أساسي:

const foo& f = foo();

MSVC ليس كذلك. إنه يصنع foo في الوظيفة ، قم بنسخها إلى الخارج (ergo the copy-constructor call) ، تدمير الداخلية foo, ثم يربط المرجع.

كلا المخرجات صحيحة. RVO هي مثيل واحد حيث يسمح المعيار صراحةً بالسلوك الملحوظ للبرنامج للتغيير.

نصائح أخرى

أنت ترى تحسين قيمة الإرجاع, ، وهو نوع واحد من نسخ elision. كلا البرنامجين صحيحان ؛ يتم إعطاء المترجم على وجه التحديد خيار التخلص من مؤقت يعمل فقط على نقل البيانات من كائن دائم إلى آخر.

تقوم وظيفة GET () ببناء المحلية (بناء الطباعة!) ، وإعادة كائن FOO حسب القيمة. يجب إنشاء كائن FOO الذي يتم إرجاعه ويتم ذلك عبر إنشاء نسخ (نسخة طباعة!). لاحظ أن هذه هي قيمة الكائن المخصصة لـ Const Foo & F باللغة الرئيسية.

قبل أن تتم هذه المهمة ، يجب أن تعود الوظيفة من GET () والمتغيرات المحلية (أي foo f ؛ في GET ()) يجب تدميرها. (طباعة أول تدمير ..) من هناك ينتهي البرنامج (أي عوائد من الرئيسية) ثم يتم تدمير الكائن الذي تم إرجاعه بواسطة GET () وتم تخصيصه إلى "F". (طباعة 2nd تدمير ...)

السبب في أنك ترى إخراجًا مختلفًا للمترجمين هو أن GCC تعمل على تحسين قيمة الإرجاع لـ GET () وهي ببساطة استبدال const foo &f = get() ل const foo &f = foo;

1) يحدث هذا بسبب استراتيجية التحسين المختلفة. نظرًا لأنه ليس لديك عامل = ، يمكن لـ MSVC إعادة هيكلة رمز إلى شيء مثل const foo & f (get ()) وبالتالي تنفيذ نسخة onstructor. 2) يعتمد على ما تريد تحقيقه:

const foo& f = get();
f = get(); // Incorrect, const references cannot be reassigned.
const foo g = get();
g = get(); // Correct.
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top