مرجع سريع لفئات قيمة C ++: الجزء 1

صورة

الهدف من هذا المرجع السريع هو الجمع في مكان واحد وتنظيم المعلومات حول فئات القيمة في C ++ ، الواجب ، تمرير المعلمة والعودة من الوظائف. حاولت جعل هذا المرجع السريع مناسبًا لمقارنة أحد الحلول الممكنة وتحديدها بسرعة ، وهذا هو السبب في أنني صنعت العديد من الجداول هنا.


لمقدمة للموضوع ، يرجى استخدام الروابط التالية:


C ++ مراجع rvalue ونقل دلالات للمبتدئين
إعادة تحديد القيم
C ++ ينتقل للأشخاص الذين لا يعرفون أو يهتمون ما هي القيم
سكوت مايرز. فعالة الحديثة C ++. 2015
فهم تحريك الدلالات والتوجيه المثالي: الجزء الأول
فهم تحريك الدلالات والتوجيه المثالي: الجزء 2
فهم تحرك الدلالات والكمال إعادة توجيه: الجزء 3
هل نحن بحاجة إلى نقل ونسخ المهمة


فئات القيمة


صورة


بدءًا من الإصدار C ++ 11 ، يمكن أن ينتمي أي تعبير فقط إلى إحدى فئات القيم الثلاث: القيمة أو القيمة أو القيمة أو القيمة:


  • xvalue (قيمة انتهاء الصلاحية) - تعبير ، يحدد الكائن غير المؤقت ، والذي يمكن نقله
  • lvalue (القيمة اليسرى) - تعبير ، يحدد كائن غير مؤقت للوظيفة ، لا يمكن نقله
  • prvalue (rvalue الخالص) - تعبير ، والذي تهيئة كائن

صورة


يمكن تصنيف هذه الفئات الثلاث في ثلاث مجموعات متداخلة:


  • glvalue (lvalue المعمم) مجموعات lvalue و xvalue. يحتوي glvalue على عنوان في الذاكرة (له هوية) وبالتالي يمكن عادةً تعيين قيمة (إذا لم تكن const)
  • مجموعات rvalue prvalue و xvalue. يمكن نقل rvalue (xvalue) أو لا ينتمي إلى كائن موجود على الإطلاق (prvalue). يمكن تمرير rvalue لنقل المنشئات أو نقل مشغلي التعيين أو نقل المهام

لذلك ، يحتوي xvalue على عنوان في الذاكرة ويمكن نقله.


صورة


يمكنك أن ترى من الجدول أعلاه ، أن المتغيرات المسماة لقيمة lvalue ، مرجع lvalue وتصنيفات rvalue جميعها لها نفس فئة التعبير: lvalue (مظللة باللون الأحمر). على سبيل المثال ، هذا يعني أنه عند تمرير مرجع القيمة إلى دالة ، سيتم اختيار التحميل الزائد لمرجع القيمة: T&& x=T(); f(x); T&& x=T(); f(x);


الروابط:
C ++ lvalue rvalue xvalue glvalue prvalue
فئات القيمة في C ++ 17
فئات القيمة


الاختصارات في هذه المقالة


اختصارات البنائين والمشغلين والمدمرين:


  • العاصمة - المنشئ الافتراضي
  • كمبيوتر - منشئ معلمة
  • نسخة - منشئ
  • Ca - نسخ المهمة (يمكن إعادة استخدام التخزين المخصص ، على سبيل المثال للأمراض المنقولة جنسياً :: السلسلة)
  • MC - موف المنشئ
  • أماه - نقل المهمة
  • فا - تحويل مهمة المشغل
  • د - المدمرة

اختصارات فئات القيمة:


  • LV - Lvalue: T LV;
  • مرجع LR - Lvalue: T& LR = LV;
  • XV - Xvalue: move(LV)
  • PRV - rvalue النقي. حرفية أو نتيجة لاستدعاء الوظيفة ، والتي لا تعد نوع الإرجاع مرجعًا: T f() { return T(); } T f() { return T(); }
  • FR - مرجع إعادة التوجيه: auto&& FR = LV;
  • CLV - const LV. CLR - const LR. CXV - const الخامس عشر.
  • CPRV - const PRV. CPRV موجود فقط للفئات والمصفوفات. سيتم تحويل ضمني CPRV غير صفيف مثل cont int ضمنيًا إلى PRV مثل int ، على سبيل المثال في قيمة الإرجاع الدالة const int f() )
  • RV هو الخامس عشر أو PRV
  • CRV هو CXV أو CPRV

الاختصارات الأخرى:


  • PF - إعادة توجيه مثالية (باستخدام مرجع إعادة التوجيه templated لتمرير المعلمة إلى وظيفة)

تعيين فئات القيمة


يمكن اعتبار تعيين فئات القيمة بمثابة أساس لجميع الأقسام التالية. عند تعيين فئة واحدة إلى أخرى بشكل صريح دون تحويل فئة صريح ، يحدث تحويل ضمني: FROM_TYPE x; TO_TYPE y; y = x; FROM_TYPE x; TO_TYPE y; y = x; في الجدول أدناه ، يمكنك رؤية ما يحدث عندما يتم تعيين تعبير type من إلى متغير من النوع To:


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

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


صورة


الحواشي:


1 - لا تعد إشارات const auto && مراجعًا لإعادة التوجيه ، وإنما هي مراجع rvalue const ، بحيث تتصرف مثل const T&&
2 - استمر إنشاء مؤقت لعقد مُهيئ مرجعي حتى نهاية نطاق مرجعه (انظر القسم التالي). لا يعمل لتحويل قيمة الإرجاع إلى نوع الوظيفة.
3 - عند المرور الحرفي ، يحتاج إلى محدد النوع على اليمين لـ auto: auto&& = T{2};


ملاحظة:


  • لا يمكن أن تقبل مراجع القيمة غير المقيدة بالقيمة و rvalue أي أنواع const. لكن نوع غير المرجع غير الثابت يمكن أن يقبل أنواع const.
  • يمكن لمرجع Rvalue (T&&) قبول xvalue أو prvalue (XV أو PRV).
  • يمكن أن يشير مرجع القيمة (T &) إلى مرجع القيمة أو القيمة (LV أو LR)
  • الأنواع غير المرجعية تقبل أي أنواع عن طريق تحويل أو نسخ أو نقل أو RVO
  • تقبل مراجع Const Lvalue (const T& و const auto &) ومراجع إعادة التوجيه التلقائي (auto &&) أي أنواع دون نسخ أو نقل
  • لا يمكن أن تقبل مراجع Const و rvalue const (T&& ، const T &&) قيم const أو غير const (LV أو CLV).
  • لا يمكن أن يقبل LR مراجع rvalue const أو غير const (XV أو PRV أو CXV أو CPRV). يمكن CLR قبولها.
  • لا يمكن تعيين الأنواع ذات معدّلات const إلى أي أنواع بدون معدّلات const (باستثناء تلقائي ، والتي يمكن أن تصبح const إذا كانت const صريحة في الجانب الأيمن).
  • تمرير القيمة (تمرير قيمة الإرجاع أو النتيجة الحرفية أو نتيجة المنشئ) هو نفس تمرير القيمة ، ولكن يتجنب استدعاء منشئ الخطوة عند التعيين على نوع غير مرجعي
  • تمرير القيمة Prvalue (تمرير قيمة الإرجاع لوظيفة type const) هي نفس تمرير const constval ، ولكنه يتجنب استدعاء مُنشئ النسخ عند التعيين على نوع غير مرجعي
  • يمكن أن تصبح المراجع التلقائية const ، بحيث يمكن قبول المتغيرات const وغير const. أيضا ، يمكن أن تصبح مراجع const لجعل استمرار مؤقت حتى نهاية نطاق المرجع. لكن المراجع التلقائية * لا يمكن أن تصبح const إذا لم يتم تحديد ذلك بشكل صريح على الجانب الأيمن. لهذا السبب لا يمكنك تعيين rvalue إلى تلقائي &
  • يمكن أن يتلقى مرجع Const مؤقتًا ويجعله مستمراً حتى نهاية نطاق المرجع (لا يمكن الرجوع إلى مرجع const). هذا يعمل فقط داخل النطاق الحالي (مراجع الدالة المحلية ووسائط الدالة). إذا كان المرجع عضوًا في فئة ما ، فسيتم تدمير كائن مؤقت في نهاية المُنشئ أو الوظيفة وسيستمر المرجع في الإشارة إلى كائن مدمر ، وهو سلوك غير محدد.
  • Auto x = CLV; سوف نستنتج لصناعة السيارات إلى نوع غير const.

أمثلة واختبارات مع طباعة كل منشئ يسمى المشغل
 #include <iostream> #include <iomanip> #include <map> #include <vector> #include <string> using namespace std; template<class C, class T> auto contains(const C& v, const T& x) -> decltype(end(v), true) { return end(v) != std::find(begin(v), end(v), x); } template <class... Types> constexpr inline __attribute__((__always_inline__)) int UNUSED(Types&&...) { return 0; }; map<string, map<string, string>> res; vector<string> froms; vector<string> tos; string from; string to; void report(string st) { if (!from.empty() && !to.empty()) { res[from][to] += st; } cout << st << " "; } struct T { T() { report("Dc"); } T(int va) : a(va) { report("Pc"); } T(const T& other) : a(other.a) { report("Cc"); } T(T&& other) : a(std::exchange(other.a, 0)) { report("Mc"); } T& operator=(int va) { report("Va"); a = va; return *this; } T& operator=(const T& rhs) { report("Ca"); // check for self-assignment if(&rhs == this) return *this; a = rhs.a; return *this; } T& operator=(T&& rhs) { report("Ma"); // check for self-assignment if(&rhs == this) return *this; a = std::exchange(rhs.a, 0); return *this; } ~T() { report("D"); } int a = 1; }; T Fprv() { return T(); } const T Fcprv() { return T(); } void print_col(const string &st, int width) { cout << endl << left << setw(width) << st; } void test_assign(string lto, string lfrom) { from = lfrom; to = lto; res[from][to] = ""; if (!from.empty() && !to.empty()) { if (!contains(froms, from)) froms.push_back(from); if (!contains(tos, to)) tos.push_back(to); } print_col(lto + " = " + lfrom + ": ", 20); } #define TEST_ASSIGN(t, v) { \ test_assign(#t, #v); \ ts = v; \ cout << sa; \ UNUSED(s); \ cout << "-"; \ } void test_conversion() { T l; const T cl; T& lr = l; const T& clr = l; T&& rr = T(); const T&& crr = T(); auto &&fr = T(); TEST_ASSIGN(T, 8); TEST_ASSIGN(T, T()); TEST_ASSIGN(T, l); TEST_ASSIGN(T, move(l)); TEST_ASSIGN(T, cl); TEST_ASSIGN(T, move(cl)); TEST_ASSIGN(T, lr); TEST_ASSIGN(T, move(lr)); TEST_ASSIGN(T, clr); TEST_ASSIGN(T, move(clr)); TEST_ASSIGN(T, rr); TEST_ASSIGN(T, move(rr)); TEST_ASSIGN(T, crr); TEST_ASSIGN(T, move(crr)); TEST_ASSIGN(T, Fcprv()); TEST_ASSIGN(T, Fprv()); TEST_ASSIGN(T, fr); TEST_ASSIGN(T, move(fr)); TEST_ASSIGN(const T, 8); TEST_ASSIGN(const T, T()); TEST_ASSIGN(const T, l); TEST_ASSIGN(const T, move(l)); TEST_ASSIGN(const T, cl); TEST_ASSIGN(const T, move(cl)); TEST_ASSIGN(const T, lr); TEST_ASSIGN(const T, move(lr)); TEST_ASSIGN(const T, clr); TEST_ASSIGN(const T, move(clr)); TEST_ASSIGN(const T, rr); TEST_ASSIGN(const T, move(rr)); TEST_ASSIGN(const T, crr); TEST_ASSIGN(const T, move(crr)); TEST_ASSIGN(const T, Fcprv()); TEST_ASSIGN(const T, Fprv()); TEST_ASSIGN(const T, fr); TEST_ASSIGN(const T, move(fr)); //TEST_ASSIGN(T&, 8); //TEST_ASSIGN(T&, T()); TEST_ASSIGN(T&, l); //TEST_ASSIGN(T&, move(l)); //TEST_ASSIGN(T&, cl); //TEST_ASSIGN(T&, move(cl)); TEST_ASSIGN(T&, lr); //TEST_ASSIGN(T&, move(lr)); //TEST_ASSIGN(T&, clr); //TEST_ASSIGN(T&, move(clr)); //TEST_ASSIGN(T&, rr); //TEST_ASSIGN(T&, move(rr)); //TEST_ASSIGN(T&, crr); //TEST_ASSIGN(T&, move(crr)); //TEST_ASSIGN(T&, Fcprv()); //TEST_ASSIGN(T&, Fprv()); TEST_ASSIGN(T&, fr); //TEST_ASSIGN(T&, move(fr)); TEST_ASSIGN(const T&, 8); TEST_ASSIGN(const T&, T()); TEST_ASSIGN(const T&, l); TEST_ASSIGN(const T&, move(l)); TEST_ASSIGN(const T&, cl); TEST_ASSIGN(const T&, move(cl)); TEST_ASSIGN(const T&, lr); TEST_ASSIGN(const T&, move(lr)); TEST_ASSIGN(const T&, clr); TEST_ASSIGN(const T&, move(clr)); TEST_ASSIGN(const T&, rr); TEST_ASSIGN(const T&, move(rr)); TEST_ASSIGN(const T&, crr); TEST_ASSIGN(const T&, move(crr)); TEST_ASSIGN(const T&, Fcprv()); TEST_ASSIGN(const T&, Fprv()); TEST_ASSIGN(const T&, fr); TEST_ASSIGN(const T&, move(fr)); TEST_ASSIGN(T&&, 8); TEST_ASSIGN(T&&, T()); //TEST_ASSIGN(T&&, l); TEST_ASSIGN(T&&, move(l)); //TEST_ASSIGN(T&&, cl); //TEST_ASSIGN(T&&, move(cl)); //TEST_ASSIGN(T&&, lr); TEST_ASSIGN(T&&, move(lr)); //TEST_ASSIGN(T&&, clr); //TEST_ASSIGN(T&&, move(clr)); //TEST_ASSIGN(T&&, rr); TEST_ASSIGN(T&&, move(rr)); //TEST_ASSIGN(T&&, crr); //TEST_ASSIGN(T&&, move(crr)); //TEST_ASSIGN(T&&, Fcprv()); TEST_ASSIGN(T&&, Fprv()); //TEST_ASSIGN(T&&, fr); TEST_ASSIGN(T&&, move(fr)); TEST_ASSIGN(const T&&, 8); TEST_ASSIGN(const T&&, T()); //TEST_ASSIGN(const T&&, l); TEST_ASSIGN(const T&&, move(l)); //TEST_ASSIGN(const T&&, cl); TEST_ASSIGN(const T&&, move(cl)); //TEST_ASSIGN(const T&&, lr); TEST_ASSIGN(const T&&, move(lr)); //TEST_ASSIGN(const T&&, clr); TEST_ASSIGN(const T&&, move(clr)); //TEST_ASSIGN(const T&&, rr); TEST_ASSIGN(const T&&, move(rr)); //TEST_ASSIGN(const T&&, crr); TEST_ASSIGN(const T&&, move(crr)); TEST_ASSIGN(const T&&, Fcprv()); TEST_ASSIGN(const T&&, Fprv()); //TEST_ASSIGN(const T&&, fr); TEST_ASSIGN(const T&&, move(fr)); //TEST_ASSIGN(auto&, T{8}); //TEST_ASSIGN(auto&, T()); TEST_ASSIGN(auto&, l); //TEST_ASSIGN(auto&, move(l)); TEST_ASSIGN(auto&, cl); TEST_ASSIGN(auto&, move(cl)); TEST_ASSIGN(auto&, lr); //TEST_ASSIGN(auto&, move(lr)); TEST_ASSIGN(auto&, clr); TEST_ASSIGN(auto&, move(clr)); TEST_ASSIGN(auto&, rr); //TEST_ASSIGN(auto&, move(rr)); TEST_ASSIGN(auto&, crr); TEST_ASSIGN(auto&, move(crr)); TEST_ASSIGN(auto&, Fcprv()); //TEST_ASSIGN(auto&, Fprv()); TEST_ASSIGN(auto&, fr); //TEST_ASSIGN(auto&, move(fr)); TEST_ASSIGN(const auto&, T{8}); TEST_ASSIGN(const auto&, T()); TEST_ASSIGN(const auto&, l); TEST_ASSIGN(const auto&, move(l)); TEST_ASSIGN(const auto&, cl); TEST_ASSIGN(const auto&, move(cl)); TEST_ASSIGN(const auto&, lr); TEST_ASSIGN(const auto&, move(lr)); TEST_ASSIGN(const auto&, clr); TEST_ASSIGN(const auto&, move(clr)); TEST_ASSIGN(const auto&, rr); TEST_ASSIGN(const auto&, move(rr)); TEST_ASSIGN(const auto&, crr); TEST_ASSIGN(const auto&, move(crr)); TEST_ASSIGN(const auto&, Fcprv()); TEST_ASSIGN(const auto&, Fprv()); TEST_ASSIGN(const auto&, fr); TEST_ASSIGN(const auto&, move(fr)); TEST_ASSIGN(auto&&, T{8}); TEST_ASSIGN(auto&&, T()); TEST_ASSIGN(auto&&, l); TEST_ASSIGN(auto&&, move(l)); TEST_ASSIGN(auto&&, cl); TEST_ASSIGN(auto&&, move(cl)); TEST_ASSIGN(auto&&, lr); TEST_ASSIGN(auto&&, move(lr)); TEST_ASSIGN(auto&&, clr); TEST_ASSIGN(auto&&, move(clr)); TEST_ASSIGN(auto&&, rr); TEST_ASSIGN(auto&&, move(rr)); TEST_ASSIGN(auto&&, crr); TEST_ASSIGN(auto&&, move(crr)); TEST_ASSIGN(auto&&, Fcprv()); TEST_ASSIGN(auto&&, Fprv()); TEST_ASSIGN(auto&&, fr); TEST_ASSIGN(auto&&, move(fr)); TEST_ASSIGN(const auto&&, T{8}); TEST_ASSIGN(const auto&&, T()); //TEST_ASSIGN(const auto&&, l); TEST_ASSIGN(const auto&&, move(l)); //TEST_ASSIGN(const auto&&, cl); TEST_ASSIGN(const auto&&, move(cl)); //TEST_ASSIGN(const auto&&, lr); TEST_ASSIGN(const auto&&, move(lr)); //TEST_ASSIGN(const auto&&, clr); TEST_ASSIGN(const auto&&, move(clr)); //TEST_ASSIGN(const auto&&, rr); TEST_ASSIGN(const auto&&, move(rr)); //TEST_ASSIGN(const auto&&, crr); TEST_ASSIGN(const auto&&, move(crr)); TEST_ASSIGN(const auto&&, Fcprv()); TEST_ASSIGN(const auto&&, Fprv()); //TEST_ASSIGN(const auto&&, fr); TEST_ASSIGN(const auto&&, move(fr)); cout << endl; const int twidth = 9; cout << left << setw(twidth) << "From:"; for (const auto& lto : tos) { cout << left << setw(twidth) << lto; } cout << endl; for (const auto& lfrom : froms) { cout << left << setw(twidth) << lfrom; for (const auto& lto : tos) { if (!res.count(lfrom) || !res[lfrom].count(lto)) { cout << left << setw(twidth) << "-"; } else if (res[lfrom][lto].empty()) { cout << left << setw(twidth) << "+"; } else { cout << left << setw(twidth) << res[lfrom][lto]; } } cout << endl; } cout << endl; } int main() { test_conversion(); cout << endl; return 0; } /* Output: Dc Dc Dc Dc Dc T = 8: Pc 8-D T = T(): Dc 1-D T = l: Cc 1-D T = move(l): Mc 1-D T = cl: Cc 1-D T = move(cl): Cc 1-D T = lr: Cc 0-D T = move(lr): Mc 0-D T = clr: Cc 0-D T = move(clr): Cc 0-D T = rr: Cc 1-D T = move(rr): Mc 1-D T = crr: Cc 1-D T = move(crr): Cc 1-D T = Fcprv(): Dc 1-D T = Fprv(): Dc 1-D T = fr: Cc 1-D T = move(fr): Mc 1-D const T = 8: Pc 8-D const T = T(): Dc 1-D const T = l: Cc 0-D const T = move(l): Mc 0-D const T = cl: Cc 1-D const T = move(cl): Cc 1-D const T = lr: Cc 0-D const T = move(lr): Mc 0-D const T = clr: Cc 0-D const T = move(clr): Cc 0-D const T = rr: Cc 0-D const T = move(rr): Mc 0-D const T = crr: Cc 1-D const T = move(crr): Cc 1-D const T = Fcprv(): Dc 1-D const T = Fprv(): Dc 1-D const T = fr: Cc 0-D const T = move(fr): Mc 0-D T& = l: 0- T& = lr: 0- T& = fr: 0- const T& = 8: Pc 8-D const T& = T(): Dc 1-D const T& = l: 0- const T& = move(l): 0- const T& = cl: 1- const T& = move(cl): 1- const T& = lr: 0- const T& = move(lr): 0- const T& = clr: 0- const T& = move(clr): 0- const T& = rr: 0- const T& = move(rr): 0- const T& = crr: 1- const T& = move(crr): 1- const T& = Fcprv(): Dc 1-D const T& = Fprv(): Dc 1-D const T& = fr: 0- const T& = move(fr): 0- T&& = 8: Pc 8-D T&& = T(): Dc 1-D T&& = move(l): 0- T&& = move(lr): 0- T&& = move(rr): 0- T&& = Fprv(): Dc 1-D T&& = move(fr): 0- const T&& = 8: Pc 8-D const T&& = T(): Dc 1-D const T&& = move(l): 0- const T&& = move(cl): 1- const T&& = move(lr): 0- const T&& = move(clr): 0- const T&& = move(rr): 0- const T&& = move(crr): 1- const T&& = Fcprv(): Dc 1-D const T&& = Fprv(): Dc 1-D const T&& = move(fr): 0- auto& = l: 0- auto& = cl: 1- auto& = move(cl): 1- auto& = lr: 0- auto& = clr: 0- auto& = move(clr): 0- auto& = rr: 0- auto& = crr: 1- auto& = move(crr): 1- auto& = Fcprv(): Dc 1-D auto& = fr: 0- const auto& = T{8}: Pc 8-D const auto& = T(): Dc 1-D const auto& = l: 0- const auto& = move(l): 0- const auto& = cl: 1- const auto& = move(cl): 1- const auto& = lr: 0- const auto& = move(lr): 0- const auto& = clr: 0- const auto& = move(clr): 0- const auto& = rr: 0- const auto& = move(rr): 0- const auto& = crr: 1- const auto& = move(crr): 1- const auto& = Fcprv(): Dc 1-D const auto& = Fprv(): Dc 1-D const auto& = fr: 0- const auto& = move(fr): 0- auto&& = T{8}: Pc 8-D auto&& = T(): Dc 1-D auto&& = l: 0- auto&& = move(l): 0- auto&& = cl: 1- auto&& = move(cl): 1- auto&& = lr: 0- auto&& = move(lr): 0- auto&& = clr: 0- auto&& = move(clr): 0- auto&& = rr: 0- auto&& = move(rr): 0- auto&& = crr: 1- auto&& = move(crr): 1- auto&& = Fcprv(): Dc 1-D auto&& = Fprv(): Dc 1-D auto&& = fr: 0- auto&& = move(fr): 0- const auto&& = T{8}: Pc 8-D const auto&& = T(): Dc 1-D const auto&& = move(l): 0- const auto&& = move(cl): 1- const auto&& = move(lr): 0- const auto&& = move(clr): 0- const auto&& = move(rr): 0- const auto&& = move(crr): 1- const auto&& = Fcprv(): Dc 1-D const auto&& = Fprv(): Dc 1-D const auto&& = move(fr): 0- From: T const T T& const T& T&& const T&&auto& const auto&auto&& const auto&& 8 PcD PcD - PcD PcD PcD - - - - T() DcD DcD - DcD DcD DcD - DcD DcD DcD l CcD CcD + + - - + + + - move(l) McD McD - + + + - + + + cl CcD CcD - + - - + + + - move(cl) CcD CcD - + - + + + + + lr CcD CcD + + - - + + + - move(lr) McD McD - + + + - + + + clr CcD CcD - + - - + + + - move(clr)CcD CcD - + - + + + + + rr CcD CcD - + - - + + + - move(rr) McD McD - + + + - + + + crr CcD CcD - + - - + + + - move(crr)CcD CcD - + - + + + + + Fcprv() DcD DcD - DcD - DcD DcD DcD DcD DcD Fprv() DcD DcD - DcD DcD DcD - DcD DcD DcD fr CcD CcD + + - - + + + - move(fr) McD McD - + + + - + + + T{8} - - - - - - - PcD PcD PcD DDDDD */ 

تهيئة مراجع ثابتة مع كائنات مؤقتة


يسمح C ++ لتهيئة مرجع ثابت مع كائن مؤقت. في هذه الحالة ، سيتم تمديد عمر كائن مؤقت. على سبيل المثال:


 struct T { int i = 1; }; const T& t = T(); cout << ti; 

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


 class A { public: // Will not compile: value-initialization of reference type //A() : t() {} const T& t; }; class B { public: // Will compile in some compilers, but temporary object will be destructed at the end of constructor B() : t(T()) { cout << "In constructor: " << ti << endl; } const T& t; }; class C { public: // Will compile, but temporary object will be destructed at the end of constructor // Address sanitizer will show the problem C() : t(std::move(T())) { cout << "In constructor: " << ti << endl; } const T& t; }; C c; cout << "C: " << cti << endl; 

بدون عنوان sanitizer هذا البرنامج سوف يخرج بعض القمامة ، ومع عنوان sanitizer سيظهر خطأ. لهذا السبب ، يجب عدم استخدام ميزة c + + أو استخدامها بحذر.


الروابط:
التهيئة المرجعية
Const مراجع إلى كائنات مؤقتة
حول ربط إشارة const إلى كائن فرعي مؤقت




انتقل إلى الجزء 2

Source: https://habr.com/ru/post/ar479342/


All Articles