sort - stl c++ شرح




هل يمكنني الحصول على حاويات متعددة الأشكال ذات دلالات قيمة في C++؟ (6)

نلقي نظرة على static_cast و reinterpret_cast
في لغة البرمجة C ++، 3rd إد، بجارن ستروستروب تصفها في صفحة 130. هناك قسم كامل في هذا في الفصل 6.
يمكنك إعادة صياغة فئة الوالدين إلى فئة الطفل. وهذا يتطلب منك أن تعرف متى كل واحد هو الذي. في الكتاب، الدكتور ستروستروب يتحدث عن تقنيات مختلفة لتجنب هذا الوضع.

لا تفعل هذا. وهذا ينفي تعدد الأشكال التي تحاول تحقيقها في المقام الأول!

كقاعدة عامة، أفضل استخدام القيمة بدلا من دلالات المؤشر في C ++ (أي باستخدام vector<Class> بدلا من vector<Class*> ). عادة ما تكون الخسارة الطفيفة في الأداء أكثر من التي تم تجميعها لعدم الحاجة إلى تذكر حذف الكائنات التي تم تخصيصها ديناميكيا.

لسوء الحظ، لا تعمل مجموعات القيمة عندما تريد تخزين مجموعة متنوعة من أنواع الكائنات التي تستمد جميعها من قاعدة مشتركة. انظر المثال أدناه.

#include <iostream>

using namespace std;

class Parent
{
    public:
        Parent() : parent_mem(1) {}
        virtual void write() { cout << "Parent: " << parent_mem << endl; }
        int parent_mem;
};

class Child : public Parent
{
    public:
        Child() : child_mem(2) { parent_mem = 2; }
        void write() { cout << "Child: " << parent_mem << ", " << child_mem << endl; }

        int child_mem;
};

int main(int, char**)
{
    // I can have a polymorphic container with pointer semantics
    vector<Parent*> pointerVec;

    pointerVec.push_back(new Parent());
    pointerVec.push_back(new Child());

    pointerVec[0]->write(); 
    pointerVec[1]->write(); 

    // Output:
    //
    // Parent: 1
    // Child: 2, 2

    // But I can't do it with value semantics

    vector<Parent> valueVec;

    valueVec.push_back(Parent());
    valueVec.push_back(Child());    // gets turned into a Parent object :(

    valueVec[0].write();    
    valueVec[1].write();    

    // Output:
    // 
    // Parent: 1
    // Parent: 2

}

سؤالي هو: هل يمكن أن يكون لديك كعكة (قيمة الدلالات) وأكله أيضا (حاويات متعددة الأشكال)؟ أو لا بد لي من استخدام مؤشرات؟


أردت فقط أن أشير إلى أن ناقلات <فو> عادة ما تكون أكثر كفاءة من ناقلات <فو *>. في ناقلات <فو>، فإن كل فوس تكون متاخمة لبعضها البعض في الذاكرة. على افتراض تلب الباردة وذاكرة التخزين المؤقت، فإن القراءة الأولى إضافة الصفحة إلى تلب وسحب قطعة من ناقلات في مخابئ L #. سوف يقرأ لاحق استخدام مخبأ دافئ وتحميل تلب، مع مخبأ في بعض الأحيان مخبأ وأقل أخطاء تلب أقل تواترا.

على النقيض من ذلك مع ناقلات <فو *>: كما كنت ملء ناقلات، يمكنك الحصول على فو * الصورة من المخزن الذاكرة الخاصة بك. على افتراض أن المخزن الخاص بك ليست ذكية للغاية، (تمالوك؟) أو كنت ملء ناقلات ببطء مع مرور الوقت، وموقع كل فو من المرجح أن يكون بعيدا عن الآخر فوس: ربما فقط من قبل مئات البايت، ربما ميغا بايت بعيدا.

في أسوأ الأحوال، كما كنت تفحص من خلال ناقلات <فو *> و ديريفيرانسينغ كل مؤشر سوف تتكبد خطأ تلب وذاكرة التخزين المؤقت يغيب - وهذا في نهاية المطاف يجري أبطأ بكثير مما لو كان لديك ناقلات <فو>. (حسنا، في أسوأ حالة حقا، تم تقسيم كل فو إلى القرص، وكل قراءة يتكبد السعي القرص () وقراءة () لنقل الصفحة مرة أخرى إلى ذاكرة الوصول العشوائي.)

لذلك، والحفاظ على استخدام ناقلات <فو> كلما كان ذلك مناسبا. :-)


فقط لإضافة شيء واحد إلى جميع المعلومات 1800 قال بالفعل.

قد ترغب في إلقاء نظرة على "أكثر فعالية C ++" من قبل سكوت مايرز "البند 3: لا تعامل صفائف بوليمورفيكالي" من أجل فهم أفضل لهذه المسألة.


قد تنظر أيضا دفعة :: أي . لقد استخدمت للحاويات غير متجانسة. عند قراءة القيمة مرة أخرى، تحتاج إلى إجراء أي_استقبال. وسوف يرمي سيئة_any_cast إذا فشلت. إذا حدث ذلك، يمكنك التقاط والانتقال إلى النوع التالي.

وأعتقد أنه سوف يرمي سيئة_any_cast إذا حاولت أن أي_استقبال الطبقة المشتقة إلى قاعدتها. حاولت ذلك:

  // But you sort of can do it with boost::any.

  vector<any> valueVec;

  valueVec.push_back(any(Parent()));
  valueVec.push_back(any(Child()));        // remains a Child, wrapped in an Any.

  Parent p = any_cast<Parent>(valueVec[0]);
  Child c = any_cast<Child>(valueVec[1]);
  p.write();
  c.write();

  // Output:
  //
  // Parent: 1
  // Child: 2, 2

  // Now try casting the child as a parent.
  try {
      Parent p2 = any_cast<Parent>(valueVec[1]);
      p2.write();
  }
  catch (const boost::bad_any_cast &e)
  {
      cout << e.what() << endl;
  }

  // Output:
  // boost::bad_any_cast: failed conversion using boost::any_cast

كل ما قيل، وأود أيضا أن تذهب إلى مسار المشتركة أولا! مجرد التفكير في هذا قد يكون من الفائدة.


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

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

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

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

وأعتقد أنه يمكن القيام به، ولكن عليك أن توفر مغلقة إلى حد ما، C # -إدارة-تشبه رمز العالم داخل C ++ (على الرغم من واحد من الذي يمكن أن تنتقل إلى C ++ الكامنة عند الحاجة). لذلك لدي الكثير من التعاطف مع خط الفكر الخاص بك.


نعم، يمكنك.

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





stl