سؤال

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

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

المحلول

اجابة قصيرة: أنت لا.

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

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

حظ سعيد.

نصائح أخرى

يعتمد على ما تقصد به "المحذوف". إذا لم تكن في مؤشر ذكي، فلن يتم حذفها صراحة، فلن يتم حذفها. الأعضاء الذين هم مجرد جزء من الفصل:

class Bar {
//...
private: 
  Foo foo;
};

لا يتم حذفه بواسطة المدمر (لأنهم لم يتم تخصيصهم ديناميكيا)، يتم تدميرها للتو. إنهم "يعيشون" داخل الفصل، لذلك بمجرد تدميره، فقد ذهب.

إذا كنت تبحث عن "الملكية" بين موقعين، فإن ما تريده هو Shared_ptr مخصص ديناميكيا:

#include <memory>
class Bar {
// ...
private:
  std::tr1::shared_ptr<Foo> foo;
};

إذا كان العضو الوارد القيمة (ليس حسب المؤشر أو بالرجوع إليه) ثم لا يمكنك منعه من حذفه ويجب ألا تريد ذلك.

إذا كنت ترغب في حذفها في أي مكان آخر بدلا من ذلك، فاجعلها موجودة بمؤشر أو بالرجوع إليها.

class House
{
  Door door; //contained by value, will be destroyed when the House is
}

class House
{
  Door& door; //contained by reference, will not be destroyed when the House is
}

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

يمكن الحصول على ما تريد القيام به باستخدام مشاركت shared_ptr، حيث يشارك كل من صفك والرمز الخارجي مؤشرا إلى نفس الكائن الخارجي. بهذه الطريقة، فقط عندما تخرج جميع المؤشرات إلى هذا الكائن من النطاق الذي سيتم حذفه. ولكن احذر عدم القيام بالمراجع الدائرية، Shared_ptr لا يوجد لديه حكمة "جامع القمامة".

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

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

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

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

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

بادئ ذي بدء، هل هذا غير معقول تماما؟

لن أقول غير معقول، ربما مشكوك فيها.

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

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

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

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


class Foo
{
public:
  Foo() {p = new int;}
 ~Foo(){}

private:
 int a;
 int *p;
};

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

لذلك في مثالنا، a سيتم تدميرها عند استدعاء المدمرين، وكذلك p, ، ولكن ليس مهما كان p نقاط ل. إذا كنت ترغب في تحرير الذاكرة التي p نقاط، المدمر ل Foo يجب أن تبدو مثل هذا:


~Foo() {delete p};

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

كيف لم يحدث أي شخص آخر ضعيف ومؤشرات قوية؟
مؤشر قوي هو مؤشر ذكي يعمل بشكل طبيعي.
مؤشر ضعيف هو مؤشر ذكي لا يستطيع حذف نفسه إلا إذا كان كل المؤشرات القوية خارج نطاقه.
يشير مؤشر قوي إلى الملكية، يشير مؤشر ضعيف إلى المشاركة.
ينظر الى boost.shared_ptr. و boost.weak_ptr. و Loki's strongptr. للتطبيقات.
أيضا إلقاء نظرة على راي. وبعد إذا كنت تعرف Raii أنك تعرف الإجابة على هذا السؤال بنفسك.

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

(أول مورد يديره الناس يشعرون بالقلق عموما هو الذاكرة، ولكن أي شيء يمكن أن تسرب - الذاكرة، مقابض الملفات، مؤشرات IDispatch - يجب أن يحتوي على رمز يتعامل مع التنظيف ضمنيا).

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

بالنسبة للموارد المدارة غير المشتركة (وخاصة تلك التي يجب إدارتها بشكل صحيح عندما يمكن إلقاء الاستثناءات)، فإن Auto_Ptr أو تغيير آخر قد يكون أكثر ملاءمة.

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

هذا ممكن ولكن أساسا كما قال ddmckee إنه مشكلة ملكية. إذا كان الأمر كذلك، فقد تكون الحال، فيمكنك الذهاب إلى إعادة النظر في Refcounting. بمعنى آخر

class A
{

RefObj* obj;
A()
{

obj = new RefObj;

}

~A()
{
 obj->ReleaseRef();
}
}


RefObj
{

int m_iRefCounter;
RefObj()
{
m_iRefCounter = 1;
}
AddRef()
{
m_iRefCounter++;
}
ReleaseRef()
{
m_iRefCounter--
if(m_iRefCounter == 0)
{
 delete this;
}
}
}

}

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