سؤال

لسبب واحد أو آخر، أجبرت على توفير كل من منشئ نسخة ومشغل = لصفي. اعتقدت أنني لم أكن بحاجة operator= إذا قمت بتحديد نسخة مطولة نسخة، ولكن QList يريد واحد. وضع ذلك جانبا، أنا أكره كود الازدواجية، فهل هناك أي شيء خاطئ في القيام بذلك بهذه الطريقة؟

Fixture::Fixture(const Fixture& f) {
    *this = f;
}

Fixture& Fixture::operator=(const Fixture& f) {
    m_shape         = f.m_shape;
    m_friction      = f.m_friction;
    m_restitution   = f.m_restitution;
    m_density       = f.m_density;
    m_isSensor      = f.m_isSensor;
    return *this;
}

فقط من الفضول، لا توجد وسيلة لتبديلها بحيث يكون الجزء الأكبر من التعليمات البرمجية في Copy Ctor و operator= بطريقة أو بأخرى تستخدمها؟ حاولت return Fixture(f); لكنه لم يعجب ذلك.


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

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

المحلول

هذا سيء، لأن operator= لا يمكن الاعتماد على كائن إعداد بعد الآن. يجب عليك القيام بذلك في الاتجاه الآخر، ويمكنه استخدام IDIOM مبادلة النسخ.

في حالة وجودك فقط لنسخ جميع العناصر، يمكنك استخدام عامل التخصيص الذي تم إنشاؤه ضمنيا.

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

Fixture::Fixture():m_data(), m_size() { }

Fixture::Fixture(const Fixture& f) {
    m_data = new item[f.size()];
    m_size = f.size();
    std::copy(f.data(), f.data() + f.size(), m_data);
}

Fixture::~Fixture() { delete[] m_data; }

// note: the parameter is already the copy we would
// need to create anyway. 
Fixture& Fixture::operator=(Fixture f) {
    this->swap(f);
    return *this;
}

// efficient swap - exchanging pointers. 
void Fixture::swap(Fixture &f) {
    using std::swap;
    swap(m_data, f.m_data);
    swap(m_size, f.m_size);
}

// keep this in Fixture's namespace. Code doing swap(a, b)
// on two Fixtures will end up calling it. 
void swap(Fixture &a, Fixture &b) {
  a.swap(b);
}

هذه هي الطريقة التي أكتب فيها مشغل الواجب عادة. اقرأ تريد السرعة؟ تمرير القيمة حول توقيع مشغل الواجب غير العادي (تمرير حسب القيمة).

نصائح أخرى

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

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

أعتقد أنك تعمل في مشكلات إذا أصبح المشغل الخاص بك = من أي وقت مضى الظاهري.

أود أن أوصي بكتابة وظيفة (ربما ثابتة) التي تحتوي النسخة ثم لديك نسخ منشئ ومشغل = استدعاء هذه الوظيفة بدلا من ذلك.

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

في كتاب جيمس كوبلين 1991 متقدم C ++., ، يوصف هذا كجزء من "النموذج القانوني الأرثوذكسية". في ذلك، يدافع عن منشئ افتراضي، منشئ نسخة، مشغل الواجب ومدمر.

بشكل عام، أنت يجب استخدم النموذج القانوني الأرثوذكسية إذا:

  • تريد دعم تعيين كائن الفئة، أو ترغب في نقل هذه الكائنات كممعلمات ذات قيمة استدعاء إلى وظيفة، و
  • يحتوي الكائن على مؤشرات على الكائنات التي يتم احتسابها المرجعية، أو يؤدي Deper Destructor delete على عضو بيانات الكائن.

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

تقدم Coplien صفحات من الأسباب لهذا النمط ولم أستطع أن أفعلها من العدالة هنا. ومع ذلك، فإن العنصر الرئيسي الذي تم لمسه بالفعل هو القدرة على تنظيف الكائن الذي يتم الكتابة فوقه.

أعتقد أنه يجب عليك تهيئة متغيرات أعضاء الكائنات الخاصة بك باستخدام initializer list. وبعد إذا المتغيرات الخاصة بك هي primitive-types, ، ثم لا يهم. خلاف ذلك، تختلف المهمة عن التهيئة.


يمكنك أن تفعل ذلك بخدعة صغيرة عن طريق تهيئة المؤشرات داخل copy constructor ل 0, ، ثم يمكنك الاتصال حذف بأمان في assignment operator:

Fixture::Fixture(const Fixture& f) : myptr(0) {
    *this = f;
}
Fixture& Fixture::operator=(const Fixture& f) {
    // if you have a dynamic array for example, delete other wise.
    delete[] myptr;
    myptr = new int[10];
    // initialize your array from the other object here.
    ......
    return *this;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top