سؤال

ركضت عبر enable_shared_from_this أثناء قراءة أمثلة Boost.Asio وبعد قراءة الوثائق، لا أزال في حيرة بشأن كيفية استخدام ذلك بشكل صحيح.هل يمكن لأي شخص أن يعطيني مثالاً و/أو شرحًا عندما يكون استخدام هذا الفصل منطقيًا.

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

المحلول

انها تمكنك من الحصول على صالحة shared_ptr على سبيل المثال this, ، عندما يكون كل ما لديك this. وبعد بدونها، فلن يكون لديك وسيلة للحصول على shared_ptr ل this, ، ما لم يكن لديك بالفعل واحدة كعضو. هذا المثال من توثيق التعزيز للتمكين_shared_from_this:

class Y: public enable_shared_from_this<Y>
{
public:

    shared_ptr<Y> f()
    {
        return shared_from_this();
    }
}

int main()
{
    shared_ptr<Y> p(new Y);
    shared_ptr<Y> q = p->f();
    assert(p == q);
    assert(!(p < q || q < p)); // p and q must share ownership
}

الطريقة f () إرجاع صالحة shared_ptr, ، على الرغم من أنه ليس لديه مثيل عضو. لاحظ أنه لا يمكنك ببساطة القيام بذلك:

class Y: public enable_shared_from_this<Y>
{
public:

    shared_ptr<Y> f()
    {
        return shared_ptr<Y>(this);
    }
}

سيكون المؤشر المشترك أن هذا عاد سيكون له عدد مرجعي مختلف من "السليم"، وسوف ينتهي أحدهم بفقدان وإجراء مرجع تتدلى عند حذف الكائن.

enable_shared_from_this أصبح جزءا من معيار C ++ 11. يمكنك أيضا الحصول عليها من هناك وكذلك من دفعة.

نصائح أخرى

من مقالة دكتور دوبس حول المؤشرات الضعيفة، أعتقد أن هذا المثال أسهل في الفهم (المصدر: http://drdobbs.com/cpp/184402026):

...رمز مثل هذا لن يعمل بشكل صحيح:

int *ip = new int;
shared_ptr<int> sp1(ip);
shared_ptr<int> sp2(ip);

لا أحد من الاثنين shared_ptr تعرف الكائنات شيئًا عن الآخر، لذا سيحاول كلاهما تحرير المورد عند تدميرهما.وهذا عادة ما يؤدي إلى مشاكل.

وبالمثل، إذا كانت وظيفة العضو تحتاج إلى shared_ptr الكائن الذي يمتلك الكائن الذي يتم استدعاؤه عليه، لا يمكنه إنشاء كائن سريعًا:

struct S
{
  shared_ptr<S> dangerous()
  {
     return shared_ptr<S>(this);   // don't do this!
  }
};

int main()
{
   shared_ptr<S> sp1(new S);
   shared_ptr<S> sp2 = sp1->dangerous();
   return 0;
}

يحتوي هذا الرمز على نفس المشكلة الموجودة في المثال السابق، على الرغم من أنه في شكل أكثر دقة.عندما يتم بناؤه، shared_ptكائن ص sp1 يمتلك المورد المخصص حديثا.الكود داخل وظيفة العضو S::dangerous لا يعرف عن ذلك shared_ptr الكائن، لذلك shared_ptr الكائن الذي يعود يختلف عنه sp1.نسخ الجديد shared_ptr يعترض على sp2 لا يساعد؛متى sp2 يخرج عن النطاق، فإنه سيتم الافراج عن المورد، ومتى sp1 إذا خرج عن النطاق، فسيتم تحرير المورد مرة أخرى.

طريقة تجنب هذه المشكلة هي استخدام قالب الفصل الدراسي enable_shared_from_this.يأخذ القالب وسيطة نوع قالب واحدة، وهو اسم الفئة التي تحدد المورد المُدار.يجب أن يتم اشتقاق هذه الفئة بشكل علني من القالب؛مثله:

struct S : enable_shared_from_this<S>
{
  shared_ptr<S> not_dangerous()
  {
    return shared_from_this();
  }
};

int main()
{
   shared_ptr<S> sp1(new S);
   shared_ptr<S> sp2 = sp1->not_dangerous();
   return 0;
}

عند القيام بذلك، ضع في اعتبارك أن الكائن الذي تتصل به shared_from_this يجب أن تكون مملوكة من قبل أ shared_ptr هدف.هذا لن ينجح:

int main()
{
   S *p = new S;
   shared_ptr<S> sp2 = p->not_dangerous();     // don't do this
}

إليكم شرحي، من منظور المكسرات والبراغي (إجابة أعلى "انقر فوق" معي). * لاحظ أن هذه هي نتيجة التحقيق في مصدر Shared_ptr وتمكين_shared_from_this الذي يأتي مع Visual Studio 2012. ربما يتم تطبيق محلات التحويل البرمجيات الأخرى enable_shared_from_this بشكل مختلف ... *

enable_shared_from_this<T> يضيف خاص weak_ptr<T> على سبيل المثال T التي تحمل 'عدد مرجع حقيقي واحدمثيل T.

لذلك، عندما تنشئ لأول مرة shared_ptr<T> على T * New T *، يتم تهيئة T *'s DIFFTION DIFTRE_PTR مع استرداد مقابل 1. الجديد shared_ptr يستغرق أساسا على هذا weak_ptr.

T يمكن بعد ذلك، في أساليبها، مكالمة shared_from_this للحصول على مثيل shared_ptr<T> الذي - التي ظهورها على نفس العدد المرجعي المخزن داخليا. وبعد بهذه الطريقة، لديك دائما مكان واحد حيث T*يتم تخزين عدد المرجع بدلا من وجود متعددة shared_ptr الحالات التي لا تعرف عن بعضها البعض، ويعتقد كل منهم هم shared_ptr وهذا المسؤول عن عد T وحذفه عندما يصل عدد المرجع إلى الصفر.

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

إنه بالضبط نفسه في C ++ 11 ثم في وقت لاحق: إنه لتمكين القدرة على العودة this كمؤشر مشترك منذ this يمنحك مؤشرا الخام.

في Word أخرى، يسمح لك بإيقاف تشغيل رمز مثل هذا

class Node {
public:
    Node* getParent const() {
        if (m_parent) {
            return m_parent;
        } else {
            return this;
        }
    }

private:

    Node * m_parent = nullptr;
};           

في هذا:

class Node : std::enable_shared_from_this<Node> {
public:
    std::shared_ptr<Node> getParent const() {
        std::shared_ptr<Node> parent = m_parent.lock();
        if (parent) {
            return parent;
        } else {
            return shared_from_this();
        }
    }

private:

    std::weak_ptr<Node> m_parent;
};           

طريقة أخرى هي إضافة weak_ptr<Y> m_stub عضو في class Y. وبعد ثم اكتب:

shared_ptr<Y> Y::f()
{
    return m_stub.lock();
}

مفيد عندما لا يمكنك تغيير الفئة التي تستمد منها (مثل تمديد مكتبة أشخاص أخرى). لا تنسى تهيئة العضو، على سبيل المثال m_stub = shared_ptr<Y>(this), ، لها صالحة حتى خلال منشئ.

لا بأس إذا كان هناك المزيد من الكبار مثل هذا في التسلسل الهرمي للميراث، فلن يمنع تدمير الكائن.

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

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