سؤال

لماذا هذا:

#include <string>
#include <iostream>
using namespace std;

class Sandbox
{
public:
    Sandbox(const string& n) : member(n) {}
    const string& member;
};

int main()
{
    Sandbox sandbox(string("four"));
    cout << "The answer is: " << sandbox.member << endl;
    return 0;
}

إعطاء إخراج:

الجواب هو:

بدلاً من:

الجواب هو: أربعة

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

المحلول

فقط محلي const المراجع إطالة عمر.

يحدد المعيار مثل هذا السلوك في الفقرة 8.5.3/5 ، [dcl.init.ref] ، القسم الخاص بتصريحات التصريحات المرجعية. المرجع في مثالك مرتبط بحجة المنشئ n, ، ويصبح غير صالح عند الكائن n لا بد أن يخرج من النطاق.

امتداد مدى الحياة ليس متعددًا من خلال وسيطة الوظيفة. §12.2/5 [class.temporary]:

السياق الثاني هو عندما يكون المرجع مرتبطًا مؤقتًا. المؤقتة التي تكون المرجع ملزمة أو المؤقتة التي هي الكائن الكامل إلى كائن فرعي يستمر فيه المؤقتة المترتبة على عمر المرجع باستثناء ما هو محدد أدناه. لا يزال هناك حدود مؤقتة لعضو مرجعي في CTOR-initializer الخاص بمشارك (§12.6.2 [class.base.init]) حتى يخرج المنشئ. لا يزال هناك حدود مؤقتة إلى معلمة مرجعية في استدعاء دالة (§5.2.2 [expr.call]) حتى الانتهاء من التعبير الكامل الذي يحتوي على المكالمة.

نصائح أخرى

إليك أبسط طريقة لشرح ما حدث:

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

إذا كنت ترغب في إصلاح برنامجك لعرض السلوك الذي تريده ، فقم بإجراء التغييرات التالية:

int main()
{
    string temp = string("four");    
    Sandbox sandbox(temp);
    cout << sandbox.member << endl;
    return 0;
}

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

ما أوصي به هو تعريف Sandbox.member ك const string member; سيؤدي ذلك إلى نسخ بيانات المعلمة المؤقتة إلى متغير العضو بدلاً من تعيين متغير العضو كمعلمة مؤقتة نفسها.

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

  • ال cout << "The answer is: " سوف تنبعث بت "The answer is: " داخل ال متعادل من stdout.

  • ثم << sandbox.member سيقوم بت بتزويد الإشارة المتدلية إلى operator << (ostream &, const std::string &), الذي يستدعي سلوك غير محدد.

لهذا السبب ، لا شيء مضمون أن يحدث. قد يعمل البرنامج على ما يبدو على ما يبدو أو قد يتعطل دون حتى تدفق stdout - وهذا يعني النص "الجواب هو:" لن يظهر على شاشتك.

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

بشكل عام ، يجب ألا تحتفظ أبدًا بالمراجع على المدى الطويل. المراجع جيدة للحجج أو المتغيرات المحلية ، ولا توجد أعضاء في الفصل.

أنت تشير إلى شيء اختفى. سيعمل التالي

#include <string>
#include <iostream>

class Sandbox
{

public:
    const string member = " "; //default to whatever is the requirement
    Sandbox(const string& n) : member(n) {}//a copy is made

};

int main()
{
    Sandbox sandbox(string("four"));
    std::cout << "The answer is: " << sandbox.member << std::endl;
    return 0;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top