المُدمِّر (برمجة الحاسوب)
في البرمجة كائنية التوجه ، المُدمِّر (يُختصر أحيانًا إلى dtor [ 1 ] ) هو دالة تُستدعى تلقائيًا قبل تحرير ذاكرة الكائن مباشرةً. [ 2 ] قد يحدث ذلك إما عندما يكون عمر الكائن مرتبطًا بنطاق معين ويخرج تنفيذه من هذا النطاق، أو عندما يكون مُضمَّنًا في كائن آخر انتهى عمره، أو عندما تم تخصيصه ديناميكيًا وتم تحريره صراحةً. يتمثل غرضه الرئيسي في تحرير الموارد (تخصيصات الذاكرة، والملفات أو المقابس المفتوحة، واتصالات قواعد البيانات ، وأقفال الموارد ، وما إلى ذلك) التي استحوذ عليها الكائن خلال دورة حياته، و/أو إلغاء تسجيله من الكيانات الأخرى التي قد تحتفظ بمراجع إليه. تُعد المُدمِّرات ضرورية في عملية الحصول على الموارد وتهيئة النظام (RAII).
في معظم أنواع خوارزميات جمع البيانات المهملة التلقائية ، قد يستغرق تحرير الذاكرة وقتًا طويلاً بعد أن يصبح الكائن غير قابل للوصول، مما يجعل دوال التدمير غير مناسبة للأغراض الحساسة للوقت. في هذه اللغات، يتم تحرير الموارد من خلال بنية معجمية (مثل try-finally، أو try-with-resources في بايثون with، أو try-with-resources في جافا)، أو عن طريق استدعاء دالة بشكل صريح (وهو ما يعادل الحذف الصريح)؛ وعلى وجه الخصوص، تستخدم العديد من لغات البرمجة كائنية التوجه نمط التخلص (dispose ).
بناء الجملة
- في لغة C++ : تحمل الدوال المدمرة نفس اسم الفئة التي ترتبط بها، ولكن مع إضافة علامة التلدة (على سبيل المثال، الفئة
Xالتي تحتوي على دالة إنشاءX()لها دالة مدمرة~X()). [ 2 ] - لغة C# : لها نفس بنية لغة C++ (
~X()). كانت تُسمى تاريخياً بالمدمرات، أما الآن فتُسمى بالمنهيات بسبب الالتباس. [ 3 ] - D : تم تعريفها على النحو التالي
~this()(بينما يتم تعريف المُنشئات على النحو التاليthis()). - جافا : لا توجد دوال تدمير في جافا كما هو الحال في لغتي C++ أو C#، ولكن توجد
close()طريقة مُقدمة من خلال واجهتينjava.lang.Closeable(مهملة) وjava.lang.AutoCloseable. في جافا 9 والإصدارات الأحدث، تم استبدال "دوال التدمير" بـjava.lang.ref.Cleaner. كانت جافا تحتوي سابقًا علىObject.finalize()، والتي أصبحت مهملة أيضًا. - في لغة أوبجكت باسكال : تحتوي طرق التدمير على الكلمة المفتاحية
destructorويمكن أن يكون لها أي اسم، ولكن الاصطلاح هوDestroy. - Objective-C : اسم دالة التدمير هو
dealloc. - في لغة بيرل ، يُطلق على طريقة التدمير اسم
DESTROY; وفي امتداد نظام كائنات Moose ، يُطلق عليها اسمDEMOLISH. - PHP : في PHP 5 والإصدارات الأحدث، يُطلق على دالة التدمير اسم
__destruct. لم تكن دوال التدمير موجودة في الإصدارات السابقة من PHP. [ 4 ] - بايثون : تُسمى دالة التدمير
__del__. كانت تُسمى دوال التدمير في بايثون 2، [ 5 ] وتُسمى الآن دوال الإنهاء في بايثون 3. [ 6 ] - في لغة Rust : يتم تسمية طريقة التدمير
dropوتوفيرها بواسطةstd::ops::Dropالسمة. [ 7 ] - في لغة Swift : اسم دالة التدمير هو
deinit.
توجد الكلمة المفتاحية deleteفي JavaScript و TypeScript ، ولكن على عكس C++، deleteفإنها في تلك اللغات تزيل خاصية من فئة.
تفاصيل اللغة
ج
بما أن لغة C لا تحتوي على كائنات، فهي لا تحتوي على دوال إنشاء أو هدم. ومع ذلك، يمكن محاكاتها باستخدام دوال تقوم بتخصيص الذاكرة وتدميرها، وذلك لتجريد الاستدعاءات اليدوية malloc()لها free().
#include <stdio.h> #include <stdlib.h>typedef struct { void * data ; // مورد ما، يمكن أن يكون أي شيء size_t size ; // حجم المورد } Resource ;// الدالة البانية Resource * createResource ( size_t size ) { Resource * res = ( Resource * ) malloc ( sizeof ( Resource )); if ( ! res ) { fprintf ( stderr , "فشل تخصيص الذاكرة للمورد. \n " ); return NULL ; } res -> data = malloc ( size ); if ( ! res -> data ) { fprintf ( stderr , "فشل تخصيص الذاكرة لبيانات المورد. \n " ); free ( res ); return NULL ; } res -> size = size ; return res ; }// دالة "التدمير" void destroyResource ( Resource * res ) { if ( res ) { if ( res -> data ) { free ( res -> data ); } free ( res ); } }int main () { // تخصيص مورد بحجم 50 بايت Resource * myResource = createResource ( 50 );إذا لم يكن المورد موجودًا ، فسيتم إرجاع القيمة 1 .for ( size_t i = 0 ; i < myResource- > size ; ++ i ) { (( char * ) myResource- > data )[ i ] = ( char )( i % 256 ); // بيانات وهمية فقط }printf ( "أول 10 بايتات من بيانات المورد: " ); for ( size_t i = 0 ; i < 10 ; ++ i ) { printf ( "%d " , (( char * ) myResource- > data )[ i ]); } printf ( " \n " );// تحرير المورد destroyResource ( myResource ); }ملحقات GCC
يأتي مُترجم لغة C الخاص بمجموعة مُترجمات GNU مع امتدادين يسمحان بتنفيذ المُدمرات:
destructorتسمح خاصية الدالة [ 8 ] بتعريف دوال تدمير ذات أولوية عامة: عندmain()انتهاء العملية، تُستدعى هذه الدوال حسب ترتيب الأولوية. انظر أيضًا: اختراق فن الاستغلال . [ 9 ]- تسمح سمة متغير التنظيف بإرفاق دالة تدمير بمتغير: يتم استدعاء الدالة عندما يخرج المتغير عن نطاق التعريف.
لغة سي++
يحمل المُدمِّر نفس اسم الصنف، ولكن مسبوقًا بعلامة المد ( ~ ). [ 2 ] على سبيل المثال، صنفٌ يُسمى `class` Fooسيحتوي على المُدمِّر `class` ~Foo(). لا تحتوي المُدمِّرات على مُعاملات ولا تُعيد أنواع بيانات. [ 2 ] كما ذُكر أعلاه، يتم استدعاء مُدمِّر الكائن عند انتهاء دورة حياته. [ 2 ] إذا تم إنشاء الكائن كمتغير تلقائي ، تنتهي دورة حياته ويتم استدعاء المُدمِّر تلقائيًا عند خروج الكائن من نطاق التعريف. نظرًا لأن لغة C++ لا تدعم جمع البيانات المهملة، إذا تم إنشاء الكائن باستخدام new`self` (ديناميكيًا على الذاكرة الديناميكية )، فسيتم استدعاء مُدمِّره عند deleteتطبيق عامل التشغيل `self` على مؤشر إلى الكائن. عادةً ما تحدث هذه العملية داخل مُدمِّر آخر، غالبًا ما يكون مُدمِّر كائن مؤشر ذكي .
في التسلسلات الهرمية للوراثة، يضمن تعريف مُدمِّر افتراضي في الفئة الأساسية استدعاء مُدمِّرات الفئات المشتقة بشكل صحيح عند حذف كائن عبر مؤشر إلى الفئة الأساسية. لذا، يجب أن ترث الكائنات التي يمكن حذفها بهذه الطريقة مُدمِّرًا افتراضيًا.
لا ينبغي أن يُطلق المُدمِّر أي استثناء [ 10 ] ؛ جميع المُدمِّرات مُعلَّمة ضمنيًا noexcept، ولكن يُمكن السماح لها بإطلاق استثناء إذا تم تعليمها صراحةً . إذا ورثت فئة من فئة تحتوي على مُدمِّر يُطلق استثناءً، أو كان لديها متغير عضو يُطلق مُدمِّره استثناءً، فلن يكون مُدمِّرها مُعلَّمًا ضمنيًا . [ 11 ]noexcept(false)noexcept
الأنواع العددية غير المصنفة لها ما يسمى بـمُدمِّر زائف يمكن الوصول إليه باستخدامtypedefوسيطات القالب. يُمكّن هذا التركيب من كتابة التعليمات البرمجية دون الحاجة إلى معرفة ما إذا كان هناك مُدمِّر لنوع مُحدد.
دالة f () { int a = 123 ; using Int = int ; a . ~ Int (); return a ; // تُرجع 123 }في الإصدارات القديمة من المعيار، تم تحديد أن الدوال المدمرة الزائفة ليس لها أي تأثير، ولكن تم تغيير ذلك في تقرير عيب لجعلها تنهي دورة حياة الكائن الذي يتم استدعاؤها عليه. [ 12 ]
في لغة C++/CLI ، التي تحتوي على كل من المدمرات والمنهيات ، فإن المدمر هو طريقة يكون اسمها هو اسم الفئة مسبوقًا بـ ~ ، كما هو الحال في (كما هو الحال في C#)، والمنهي هو طريقة يكون اسمها هو اسم الفئة مسبوقًا بـ ! ، كما هو الحال في .~Foo()!Foo()
يجب تعطيل الكائنات التي لا يمكن نسخها أو إسنادها بأمان من هذه الدلالات عن طريق تعريف وظائفها المقابلة على أنها محذوفة. يمكن الاطلاع على وصف مفصل لهذه الطريقة في كتاب سكوت مايرز الشهير، Effective Modern C++ (البند 11: "تفضيل الدوال المحذوفة على الدوال الخاصة غير المعرفة." [ 13 ] ). إذا تم وضع علامة deleted عليها، فيجب أن يكون ذلك publicواضحًا بحيث لا تُنذر الاستخدامات العرضية بأنها محذوفة private، بل تُشير صراحةً إلى أنها deleteمحذوفة. منذ C++26 ، أصبح من الممكن تحديد سبب الحذف.
تحتوي لغة C++ على دوال std::destroy()( std::destroy_at()بما std::destroy_n()في ذلك دوال النطاق ) التي تُنهي دورة حياة الكائن. مع ذلك، عند استدعائها على نوع غير صنفي، فإنها تستدعي فقط الدالة الوهمية للتدمير، والتي لا تُنهي دورة الحياة فعليًا.std::ranges::destroy()std::ranges::destroy_at()std::ranges::destroy_n()
مثال
استيراد std ؛باستخدام std :: formatter ؛ باستخدام std :: format_parse_context ؛class Foo { private : size_t length ; char * data ; friend struct formatter <Foo> ; public : // Constructor explicit Foo ( const char s [] = "" ) : length { std :: strlen ( s ) }, data { new char [ length + 1 ] } { std :: strcpy ( data , s ) ; }Foo ( const Foo & ) = delete ( "تم تعطيل إنشاء النسخ" ); Foo & operator = ( const Foo & ) = delete ( "تم تعطيل إسناد النسخ" );// Destructor ~ Foo () { delete [] data ; } };template <> struct std :: formatter < Foo > { // تعريف المُنسِّق لـ Foo هنا };int main ( int argc , char * argv []) { Foo foo ( "مرحباً من المكدس!" ); std :: println ( "{}" , foo );Foo * foo = new Foo ( "Hello from the heap!" ); std :: println ( "{}" , * foo ); delete foo ; }باستخدام المؤشرات الذكية مع نمط " اكتساب الموارد هو التهيئة " (RAII)، يمكن تجريد عملية تنظيف الموارد يدويًا. تتضمن لغات أخرى مثل جافا وسي شارب finallyكتلةً للتنظيف، بينما لا تحتوي لغة سي++ على هذه finallyالكتلة، بل تشجع على استخدام نمط RAII.
استيراد std ؛باستخدام std :: formatter ؛ باستخدام std :: format_parse_context ؛ باستخدام std :: unique_ptr ؛class Foo { private : size_t length ; unique_ptr < char [ ] > data ; friend struct formatter <Foo> ; public : // Constructor explicit Foo ( const char s [] = "" ) : length { std :: strlen ( s ) }, data { std :: make_unique < char [] > ( length + 1 ) } { std :: strcpy ( data.get ( ), s ) ; }Foo ( const Foo & ) = delete ( "تم تعطيل إنشاء النسخ" ); Foo & operator = ( const Foo & ) = delete ( "تم تعطيل إسناد النسخ" );// يتم التعامل مع المُدمِّر تلقائيًا بواسطة unique_ptr ~ Foo () = default ; };template <> struct std :: formatter < Foo > { // تعريف المُنسِّق لـ Foo هنا };int main ( int argc , char * argv []) { Foo foo ( "مرحباً من المكدس!" ); std :: println ( "{}" , foo );unique_ptr <Foo> foo = std :: make_unique <Foo> ( " مرحباً من الكومة!" ) ; std :: println ( "{} " , * foo ) ; }سي شارب
إن المدمر الخاص بالفئة Xفي لغة C# هو ~X()، والذي ليس له معلمات، ومثل المنشئ، ليس له نوع إرجاع.
تتضمن لغة C# نمط "dispose" الذي يُلزم الفئة بتنفيذ الواجهة System.IDisposable. كما تدعم C# كتل try-with-resources المشابهة للغة Java، والتي تُسمى using-with-resources. يجب على الفئة تنفيذ System.IDisposableهذه الواجهة لاستخدامها في كتلة using-with-resources.
namespace Wikipedia.Examples ;باستخدام System ؛ باستخدام System.Collections.Generic ؛ باستخدام System.Data.SqlClient ؛public record User ( int Id , string Name , string Email );public class UserUnitOfWork : IDisposable { private readonly SqlConnection _connection ; private SqlTransaction _transaction ; private bool _disposed ;public UserUnitOfWork ( string url ) { _connection = new ( url ); _connection . Open (); _transaction = _connection . BeginTransaction (); }public List <User> GetActiveUsers ( ) { // ... }public void Commit () { _transaction ?. Commit (); }public void Dispose () { if ( _disposed ) { return ; } try { _transaction ? .Dispose (); _connection ? .Close (); _connection ? .Dispose (); } finally { _disposed = true ; } } }class Program { static void Main ( string [] args ) { using ( UserUnitOfWork uow = new ( /* سلسلة الاتصال */ ) { Console . WriteLine ( "استخدام UserUnitOfWork..." ); List < User > users = uow . GetActiveUsers (); uow . Commit (); // ... } // تم إغلاق الاتصال والمعاملة هنا } }لا يتم استدعاء الدوال المدمرة في لغة C# يدويًا أو بواسطة deleteعامل كما هو الحال في لغة C++. بل يتم استدعاؤها فقط بواسطة جامع البيانات المهملة.

مع ذلك، لا ينبغي استخدام دوال الإنهاء إلا عند الضرورة القصوى، مثل التعامل مع الموارد غير المُدارة كالمؤشرات والمقابض الأصلية. والسبب في ذلك هو أن إضافة دالة إنهاء تنقل الكائن إلى قائمة الإنهاء وتتطلب دورتين على الأقل من جمع البيانات المهملة، مما يُبطئ الأداء ويزيد الضغط على الذاكرة.
namespace Wikipedia.Examples ;باستخدام النظام ؛class NativeResourceHolder : IDisposable { private IntPtr _nativeHandle ; private bool _disposed ;public NativeResourceHolder () { _nativeHandle = AllocateNative (); }public void Dispose () { Dispose ( true ); GC . SuppressFinalize ( this ); }// المُنهي ~ NativeResourceHolder () { Dispose ( false ); }protected virtual void Dispose ( bool disposing ) { if ( ! _dipsomed ) { // تحرير الموارد المُدارة هنا، إن وُجدت } FreeNative ( _nativeHandle ); _disposed = true ; }private IntPtr AllocateNative () => new IntPtr ( 42 ); private void FreeNative ( IntPtr ptr ) { /* ... */ } }class Program { static void Main ( string [] args ) { NativeResourceHolder obj = new (); GC . Collect (); GC . WaitForPendingFinalizers ();Console.WriteLine ( "انتهى البرنامج " ) ; } }د
يوضح ما يلي استخدام أداة التدمير في D.
استيراد std.stdio ؛struct Integer { int x ;this ( int value ) { x = value ; writeln ( "تم استدعاء الدالة البانية مع x = " , x ); }~ this () { writeln ( "تم استدعاء المُدمِّر لـ x = " , x ); } }void main () { { Integer s = Integer ( 10 ); writeln ( "داخل النطاق" ); } // يتم تنفيذ المُدمِّر هناwriteln ( "خارج النطاق" ); }جافا
في لغة جافا، توجد دوال التدمير (destroyers ~X()) كما هو الحال في لغتي C++ وC#، ولكن جافا توفر أيضًا واجهات تُنفذ close()طريقةً تُسمى `destructors`: java.lang.Closeable`destructors` (مهملة) و`destructors` . يمكن استخدام java.lang.AutoCloseableفئة تُنفذ `destructors` في كتلة `with-resources`، والتي تستدعي طريقتها تلقائيًا عند انتهاء النطاق، وهي متاحة منذ جافا 7. [ 14 ] على عكس دوال التدمير، تُستخدم الطرق لتنظيف الموارد، وليس لتحرير الذاكرة، حيث تُستعاد الذاكرة من خلال عملية جمع البيانات المهملة.java.lang.AutoCloseabletryclose()clean()
package org.wikipedia.examples ;استيراد java.sql.Connection ؛ استيراد java.sql.DriverManager ؛ استيراد java.sql.SQLException ؛ استيراد java.util.ArrayList ؛ استيراد java.util.List ؛public record User ( int id , String name , String Email ) {}class UserUnitOfWork implements AutoCloseable { private final Connection conn ; private bool committed = false ;public UserUnitOfWork ( String url , String username , String password ) throws SQLException { this.connection = DriverManager.getConnection ( url , username , password ) ; this.connection.setAutoCommit ( false ) ; }public List <User> getActiveUsers ( ) throws SQLException { // ... }public void commit () throws SQLException { connection . commit (); committed = true ; }@Override public void close () throws SQLException { try { if ( ! committed ) { connection.rollback ( ) ; } } finally { connection.close ( ) ; } } }public class Example { public static void main ( String [] args ) { try ( UserUnitOfWork uow = new UserUnitOfWork ( /* URL and credentials */ )) { System . out . println ( "Using UserUnitOfWork..." ); List < User > users = uow . getActiveUsers (); uow . commit (); // ... } // بعد try-with-resources، سيتم استدعاء d.close() } }قبل Java 7، تم استخدام كتلة " try- "، حيث تم وضع الاستدعاء داخل الكتلة.finallyd.close()finally
تاريخيًا، استخدمت لغة جافا finalize()طريقة `finalizers` java.lang.Object، إلا أنها أصبحت مهملة، إذ لا توجد ضمانات بشأن أي خيط سيستدعي هذه الطريقة لأي كائن معين، أو حتى ما إذا كانت ستُستدعى أصلًا. تُعدّ دوال `finalizers` غير حتمية (على عكس دوال التدمير في لغة C++)، وقد يؤدي finalize()تحرير الموارد الحيوية في استدعاء لها إلى سلوك غير متوقع . [ 15 ]finalize()
تحتوي لغة جافا على دالة تُسمى ` gc()in` java.lang.Systemتُشير java.lang.Runtimeإلى آلة جافا الافتراضية (JVM) لتنفيذ عملية جمع البيانات المهملة، وهي تُعادل داخليًا استدعاءً Runtime.getRuntime().gc()يطلب من جامع البيانات المهملة بدء دورة جمع البيانات المهملة، ولكن هذا ليس مضمونًا، لأن JVM تُدير الذاكرة بشكل مستقل. System.gc()قد يؤدي ذلك إلى finalize()استدعاء `in`، ولكن فقط إذا كان الكائن مؤهلًا لجمع البيانات المهملة ويحتوي على finalize()دالة `in`.
package org.wikipedia.examples ;class ParentFinalizerExample { /* ... */ }class FinalizerExample extends ParentFinalizerExample { @Override protected void finalize () throws Throwable { try { System . out . println ( "تم استدعاء finalize()، جارٍ التنظيف..." ); } finally { super . finalize (); // دائمًا استدعِ super.finalize() لتنظيف الفئات الأصلية } } }public class Example { public static void main ( String [] args ) { FinalizerExample obj = new FinalizerExample (); obj = null ; System . gc (); // يطلب جمع البيانات المهملة (غير مضمون) } }تدعم لغة جافا أيضًا الفئات java.lang.ref.Cleaner، ولتنظيف java.lang.ref.PhantomReferenceالبيانات على مستوى منخفض بشكل أكثر أمانًا. java.lang.ref.Cleanerتم تقديم هذه الميزة في جافا 9، وهي أكثر كفاءة من غيرها java.lang.ref.PhantomReference، وتعمل عن طريق تسجيل كائن في سلسلة عمليات تنظيف تقوم بتنفيذ عملية تنظيف بمجرد أن يصبح الكائن غير قابل للوصول (أي لا توجد أي مراجع له). ومثلها مثل الفئات java.lang.Closeableالأخرى java.lang.AutoCloseable، لا تستعيد هذه الميزة الذاكرة، بل يتم ذلك عن طريق جمع البيانات المهملة.
package org.wikipedia.examples ;استيراد java.lang.ref.Cleaner ؛ استيراد java.lang.ref.Cleaner.Cleanable ؛class Resource { private static final Cleaner cleaner = Cleaner . create ();static class State implements Runnable { private boolean cleaned = false ;@Override public void run () { cleaned = true ; System . out . println ( "تم التنظيف باستخدام Cleaner" ); } }حالة نهائية خاصة ؛ قابل للتنظيف نهائي خاص قابل للتنظيف ؛public Resource ( ) { this.state = new State ( ) ; this.cleanable = cleaner.register ( this , state ) ; }public void cleanup () { System . gc (); // طلب جمع البيانات المهملة (غير مضمون) } }public class Example { public static void main ( String [] args ) { Resource resource = new Resource (); resource = null ; resource . cleanup (); } }java.lang.ref.PhantomReferenceمنذ Java 1.2، تُعدّ آلية تنظيف الذاكرة القديمة هذه آليةً تستخدم قائمة انتظار المراجع. java.lang.ref.PhantomReferenceتُستخدم فقط لتلقّي إشعارٍ بأنّ عملية جمع البيانات المهملة لكائنٍ ما قيد الانتظار. بمجرد جمع البيانات المهملة للكائن، java.lang.ref.PhantomReferenceيُضاف الكائن إلى قائمة انتظار المراجع java.lang.ref.ReferenceQueue. على عكس آلية جمع java.lang.ref.WeakReferenceالبيانات المهملة التي يمكن استخدامها للوصول إلى الكائن إذا كان لا يزال موجودًا في الذاكرة، java.lang.ref.PhantomReferenceلا يمكن استخدام هذه الآلية إلا للكشف عن وقت تدمير الكائن. لا تُؤدّي كلتا الآليتين إلى زيادة عدد المراجع java.lang.ref.PhantomReference.java.lang.ref.WeakReference
package org.wikipedia.examples ;استيراد java.lang.ref.PhantomReference ؛ استيراد java.lang.ref.ReferenceQueue ؛class Resource { private final String name ;public Resource ( String name ) { this . name = name ; }public String getName () { return name ; } }public class PhantomReferenceExample { public static void main ( String [] args ) throws InterruptedException { Resource resource = new Resource ( "My resource" ); ReferenceQueue < Resource > queue = new ReferenceQueue <> (); PhantomReference < Resource > phantomRef = new PhantomReference <> ( resource , queue );المورد = لا شيء ؛System.gc ( ) ;Reference < ? extends Resource > ref = queue.poll ( ) ; if ( ref != null ) { System.out.printf ( " الكائن جاهز للاستلام: %s%n" , (( PhantomReference <?> ) ref ) .get ( ) ); } } }على عكس ما هو الحال std::weak_ptrفي لغة C++ والذي يُستخدم للإشارة إلى كائن دون زيادة عدد المراجع الخاصة به ، java.lang.ref.WeakReferenceلا يزال بإمكان المستخدم الوصول إلى الكائن بعد أن يصل عدد المراجع إلى 0، بينما في لغة C++ std::weak_ptrلا يمكن ذلك حيث يتم تدمير الكائن على الفور بمجرد أن يصل عدد المراجع الخاصة به إلى 0.
بايثون
يدعم بايثون المدمرات ويحتوي على delكلمة مفتاحية، ولكن على عكس deleteلغة C++، فإنه delيقلل فقط من عدد المراجع للكائن، ولا يقوم بالضرورة بتدمير الكائن على الفور.
class Destructible : def __init__ ( self , name : str ) -> None : self . name : str = name print ( f "تم إنشاء كائن قابل للتدمير: { self . name } " )def __del__ ( self ) -> None : print ( f "تم استدعاء المُدمِّر لـ: { self . name } " )إذا كان __name__ يساوي "__main__" : d : Destructible = Destructible ( " My name" ) print ( f " Using Destructible: { d.name } " ) del dعلى غرار لغتي جافا وسي شارب، تحتوي لغة بايثون على كتلة try-with-resources، والتي تسمى withكتلة أو "مدير سياق". تُستخدم هذه الكتلة لأشياء مثل الملفات واتصالات الشبكة.
من typing استورد Optionalclass Destructible : def __init__ ( self , name : str ) -> None : self . name : str = namedef __enter__ ( self ) -> "Destructible" : print ( f "Entering context (allocating resource : { self.name } ) " ) return selfdef __exit__ ( self , exc_type : Optional [ type ], exc_val : Optional [ Exception ], exc_tb : Optional [ type ]) -> None : print ( f "الخروج من السياق (تنظيف المورد: { self . name } )" )إذا كان __name__ يساوي "__main__" : مع Destructible ( "Resource A" ) كـ d : اطبع ( f "استخدام المورد { d . name } داخل السياق" )# تدعم معظم موارد مكتبة بايثون القياسية استخدام كتل with: with open ( file_path , "r" ) as file : print ( "قراءة محتوى الملف:" ) content : str = file . read () print ( content )الصدأ
لا تحتوي لغة Rust على مدمرات بالمعنى المتعارف عليه في البرمجة الكائنية التوجه، ولكن structيمكن تنفيذ std::ops::Dropالسمة والطريقة dropلتنظيف نفسها بعد خروجها من النطاق.
لا يمكن تدمير الكائنات بشكل صريح من خلال deleteعامل تشغيل كما هو الحال في لغة C++، على الرغم من أنه من الممكن استدعاء ذلك يدويًا drop()قبل الأوان باستخدام std::mem::drop().
استخدم std :: mem ؛struct Destructible { name : String , }impl Destructible { fn new ( name : String ) -> Self { Destructible { name } } }impl Drop for Destructible { fn drop ( & mut self ) { println! ( "Dropping Destructible: {}" , self . name ); } }fn main () { { let resource_a : Destructible = Destructible :: new ( String :: from ( "Resource A" )); println! ( "Using Destructible." ); } // <--- يخرج resource_a من نطاق التعريف هنا، ويتم استدعاء `drop()` تلقائيًاlet resource_b : Destructible = Destructible :: new ( String :: from ( "Resource B" )); println! ( "حذف Destructible قبل الأوان." ); mem :: drop ( resource_b ); }بينما تتحكم فترات الصلاحية في صلاحية المراجع، إلا أنها لا تحدد متى drop()يتم استدعاؤها.
تايب سكريبت
على الرغم من أن TypeScript لا يدعم إدارة الذاكرة اليدوية، إلا أنه يمتلك إدارة موارد مشابهة usingلكتل `with-resource` في C# أو Java ، أو ما يُعرف tryفي C++ بـ "التهيئة" أو "اكتساب الموارد" ، حيث يتم إغلاق الموارد تلقائيًا دون الحاجة إلى كتل. في TypeScript، لإغلاق كائن تلقائيًا، يجب أن يُنفذ واجهة عامة ، وأن يُنفذ دالة . سيتم استدعاء هذه الدالة تلقائيًا عند انتهاء نطاق الكائن. [ 16 ]finallyDisposableSymbol.dispose()
استورد * كـ fs من 'fs' ؛class TempFile implements Disposable { #path : string ; #handle : number ;constructor ( path : string ) { this . # path = path ; this . # handle = fs.openSync ( path , "w+" ); }write ( data : string ) : void { fs.writeSync ( this . # handle , data ) ; }[ Symbol.dispose ] ( ) : void { fs.closeSync ( this . # handle ) ; fs.unlinkSync ( this . # path ) ; } }export function doSomeWork () { using file : TempFile = new TempFile ( ".some_temp_file.txt" );إذا ( بعض الشروط ()) { // قم بشيء ما هنا } }زوجو
يمكن أن تتخذ الدوال المدمرة في Xojo (REALbasic) أحد شكلين. يستخدم كل شكل تعريفًا عاديًا للدالة باسم خاص (بدون معلمات أو قيمة إرجاع). يستخدم الشكل القديم نفس اسم الفئة مسبوقًا بعلامة المد (~). أما الشكل الأحدث فيستخدم اسمًا مختلفًا Destructor. يُفضل استخدام الشكل الأحدث لأنه يُسهّل إعادة هيكلة الفئة.
كلاس فوبار // الشكل القديم Sub ~Foobar() نهاية الإجراء الفرعي // نموذج جديد Sub Destructor() نهاية الإجراء الفرعي نهاية الفئة
انظر أيضاً
مراجع
- ^ "دتور" . TheFreeDictionary.com . تم الاسترجاع 2018/10/14 .
- 1 2 3 4 5 سيبيستا، روبرت دبليو (2012). ""11.4.2.3 المُنشئات والمُدمِّرات"مفاهيم لغات البرمجة (مطبوع) (الطبعة العاشرة ) . بوسطن، ماساتشوستس، الولايات المتحدة الأمريكية: أديسون-ويسلي. ص 487. ISBN 978-0-13-139531-2.
- ↑ "المُنهيات (دليل برمجة C#)" .
- ↑ المُنشئات والمُدمِّرات ، من وثائق PHP على الإنترنت
- ↑ "3. نموذج البيانات — وثائق بايثون 2.7.18" .
- ↑ "3. نموذج البيانات — وثائق بايثون 3.10.4" .
- ↑ "المدمرون - مرجع Rust" .
- ↑ سمة دالة "التدمير" في لغة C
- ↑ إريكسون، جون (2008). اختراق فن الاستغلال . دار نشر نو ستارش . رقم ISBN 978-1-59327-144-2.
- ↑ GotW #47: استثناءات غير معالجة تم الوصول إليها في 31 يوليو 2011.
- ↑ ISO C++. "امتدادات لغة C++11 - الميزات العامة" . isocpp.org . ISO C++ . تم الاطلاع عليه بتاريخ 11 يوليو 2026 .
- ↑ سميث، ريتشارد؛ فوتيلينن، فيل. "P0593R6: إنشاء ضمني للكائنات لمعالجة الكائنات على مستوى منخفض" . open-std.org . تم الاسترجاع في 25 نوفمبر 2022 .
- ↑ سكوت مايرز: لغة سي++ الحديثة الفعالة ، أورايلي، رقم ISBN 9781491903995
- ↑ بلوخ، جوشوا (2018). جافا الفعالة ( الطبعة الثالثة). أديسون-ويسلي . الصفحات 29-31 . ISBN 978-0134685991.
- ↑ صن مايكروسيستمز. "تجنب استخدام المُنهيات" . docs.oracle.com . صن مايكروسيستمز . تم الاطلاع عليه بتاريخ 27 مايو 2026 .
- ↑ "الوثائق - تايب سكريبت 5.2" . www.typescriptlang.org . مؤرشف من الأصل في 9 أغسطس 2024. تم الاطلاع عليه في 9 نوفمبر 2023 .
- طريقة (برمجة الحاسوب)
- لغة سي++
