الأمراض المنقولة جنسيا :: auto_ptr أو تعزيز :: shared_ptr لpImpl لغة؟

StackOverflow https://stackoverflow.com/questions/311166

سؤال

عند استخدام pImpl لغة هل من الأفضل استخدام boost:shared_ptr بدلا من std::auto_ptr؟ أنا متأكد من أن قرأت مرة أن إصدار دفعة هو أكثر ودية استثناء؟

class Foo
{
public:
    Foo();
private:
    struct impl;
    std::auto_ptr<impl> impl_;
};

class Foo
{
public:
    Foo();
private:
    struct impl;
    boost::shared_ptr<impl> impl_;
};

[تحرير] هل دائما آمنة للاستخدام الأمراض المنقولة جنسيا :: auto_ptr <> أم أن هناك حالات عندما يكون مطلوبا مؤشر ذكية دفعة البديل؟

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

المحلول

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

إذا كنت تستخدم تعزيز :: scoped_ptr ( لا حاجة لshared_ptr هنا، فلن تكون تقاسم pimpl مع أي أجسام أخرى، وهذا ما فرضته scoped_ptr كونها <لأ href = "http://www.boost.org/doc/libs/1_37_0/libs/utility /utility.htm#Class_noncopyable "يختلط =" noreferrer "> noncopyable )، تحتاج فقط المدمر pimpl مرئية عند نقطة استدعاء منشئ scoped_ptr.

ومنها مثلا.

// in MyClass.h

class Pimpl;

class MyClass 
{ 
private:
    std::auto_ptr<Pimpl> pimpl;

public: 
    MyClass();
};

// Body of these functions in MyClass.cpp

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

ودفعة :: scoped_ptr (وshared_ptr) لم يكن لديك هذه المشكلة، وذلك لأن عند استدعاء منشئ من scoped_ptr (أو طريقة إعادة تعيين) فإنه يجعل أيضا وظيفة مؤشر ما يعادل أنها سوف تستخدم بدلا من استدعاء حذف . والنقطة الأساسية هنا هي أنه instantiates وظيفة إلغاء تخصيص عندما Pimpl ليس نوع غير مكتملة. كملاحظة جانبية، shared_ptr يسمح لك بتحديد مخصصة إلغاء تخصيص وظيفة، لذلك يمكنك استخدامها لأنها لأشياء مثل GDI يعالج أو أي شيء آخر قد ترغب - ولكن هذا مبالغة لاحتياجاتك هنا

إذا كنت تريد حقا أن استخدام الأمراض المنقولة جنسيا :: auto_ptr، فأنت بحاجة لرعاية اضافية عن طريق التأكد من أن تحدد المدمر MyClass بك في MyClass.cpp عند تعريف Pimpl بالكامل.

// in MyClass.h

class Pimpl;

class MyClass 
{ 
private:
    std::auto_ptr<Pimpl> pimpl;

public: 
    MyClass();
    ~MyClass();
};

و

// in MyClass.cpp

#include "Pimpl.h"

MyClass::MyClass() : pimpl(new Pimpl(blah))
{
}

MyClass::~MyClass() 
{
    // this needs to be here, even when empty
}

والمترجم سوف تولد التدمير كود جميع أعضاء MyClass فعال 'في' والمدمر فارغة. لذلك عند نقطة إنشاء مثيل المدمر auto_ptr، Pimpl لم تعد ناقصة والمترجم يعرف الآن كيفية استدعاء المدمر.

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

نصائح أخرى

وأنا أميل إلى استخدام auto_ptr. التأكد من أن تكون صفك noncopyable (إعلان الخاص نسخة المنشئ والمشغل =، وإلا ترث boost::noncopyable). إذا كنت تستخدم auto_ptr، تجاعيد واحد هو أن تحتاج إلى تعريف المدمر غير مضمنة، حتى لو كان الجسم فارغ. (وهذا هو لأنه إذا ما تركت المترجم توليد المدمر الافتراضي، impl سيكون نوع غير مكتمل عندما يتم إنشاء الدعوة إلى delete impl_، استدعاء سلوك غير معرف).

وهناك القليل للاختيار بين auto_ptr ومؤشرات دفعة. أنا لا تميل إلى استخدام دفعة على أسس الأسلوبية إذا كان البديل مكتبة القياسية وسوف نفعل.

تم تصميم دفعة :: shared_ptr خصيصا للعمل من أجل لغة pimpl. واحدة من المزايا الرئيسية هو أنه لا يسمح لتحديد المدمر للpimpl الطبقة القابضة. مشترك سياسة الملكية ربما على حد سواء ميزة وعيب. ولكن في حالة لاحقة يمكنك تحديد نسخة منشئ بشكل صحيح.

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

واحد الاختلاف هو استخدام const auto_ptr. يعمل هذا طالما يمكنك بناء بلدكم pimpl 'مع تعبير جديد داخل القائمة initialiser ويضمن المترجم <م> لا يمكن توليد نسخة منشئ افتراضي والأساليب الواجب. A المدمر غير مضمنة للطبقة أرفق لا يزال يحتاج إلى المقدمة.

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

إذا كنت ترغب في الطبقة copyable، استخدم scoped_ptr، الذي يمنع النسخ، مما يجعل صفك من الصعب استخدام خاطئ بشكل افتراضي (مقارنة باستخدام shared_ptr، فإن المترجم لا تنبعث منها مرافق نسخة من تلقاء نفسها، وفي حالة shared_ptr ، إذا كنت لا تعرف ما تفعله [التي غالبا ما تكون كافية الحال حتى عن المعالجات]، لن يكون هناك سلوك غريب عندما فجأة بتعديل نسخة من شيء أيضا أن شيئا)، ومن ثم خارج تحدد نسخة-منشئ ونسخ -assignment:

class CopyableFoo {
public:
    ...
    CopyableFoo (const CopyableFoo&);
    CopyableFoo& operator= (const CopyableFoo&);
private:
    scoped_ptr<Impl> impl_;
};

...
CopyableFoo (const CopyableFoo& rhs)
    : impl_(new Impl (*rhs.impl_))
{}

وshared_ptr هو الأفضل بكثير لauto_ptr لpImpl لأن الطبقة الخارجية الخاصة بك يمكن أن ينتهي فجأة يفقد المؤشر به عند نسخها.

ومع shared_ptr يمكنك استخدام نوع أعلن بشكل إلى الأمام بحيث يعمل. auto_ptr لا يسمح نوع أعلن بشكل إلى الأمام. كما لا scoped_ptr وإذا الطبقة الخارجية الخاصة بك سوف تكون غير copyable على أي حال، وليس لديها سوى مؤشر واحد، فإنه قد يكون جيدا كما واحد منتظم.

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

ولقد كنت سعيدا حقا عن <لأ href = "http://www.codeproject.com/Articles/11903/Two-thirds-of-a-pimpl-and-a-grin؟msg=2690869#xx2690869xx" يختلط = "نوفولو"> impl_ptr فلاديمير Batov [تعديل] . انه يجعل من السهل حقا لخلق pImpl دون الحاجة إلى جعل صريح نسخ منشئ وتعيين المشغل.

ولقد تعديل التعليمات البرمجية الأصلية، لذلك يشبه الآن shared_ptr، لذلك يمكن استخدامها في التعليمات البرمجية الخاتمة، ويبقى وجه السرعة.

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

ويبقيه بسيط.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top