ما فائدة "تمكين_المشاركه_من_هذا"؟
-
23-08-2019 - |
سؤال
ركضت عبر 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 عند الانتهاء من المهمة وتدمير المتغيرات المؤقتة. لذلك جوابي غير صحيح.