Seperti yang Anda duga, ya, C ++ menyediakan kemampuan yang sama tanpa mekanisme itu. Dengan demikian, tegasnya, yang try
/ finally
mekanisme tidak benar-benar diperlukan.
Yang mengatakan, melakukan tanpa itu memberlakukan beberapa persyaratan pada cara sisa bahasa dirancang. Dalam C ++ set tindakan yang sama diwujudkan dalam destruktor kelas. Ini berfungsi terutama (secara eksklusif?) Karena doa destruktor dalam C ++ bersifat deterministik. Ini, pada gilirannya, mengarah pada beberapa aturan yang agak rumit tentang masa hidup objek, beberapa di antaranya jelas tidak intuitif.
Sebagian besar bahasa lain menyediakan beberapa bentuk pengumpulan sampah. Meskipun ada hal-hal tentang pengumpulan sampah yang kontroversial (misalnya, efisiensinya relatif terhadap metode lain manajemen memori) satu hal yang umumnya tidak: waktu yang tepat ketika suatu objek akan "dibersihkan" oleh pengumpul sampah tidak terikat langsung ke ruang lingkup objek. Ini mencegah penggunaannya ketika pembersihan harus bersifat deterministik baik ketika itu hanya diperlukan untuk operasi yang benar, atau ketika berhadapan dengan sumber daya yang sangat berharga sehingga pembersihan mereka paling tidak ditunda secara sewenang-wenang. try
Saya finally
menyediakan cara bagi bahasa-bahasa semacam itu untuk menghadapi situasi-situasi yang mengharuskan pembersihan deterministik.
Saya pikir orang-orang yang mengklaim bahwa sintaks C ++ untuk kemampuan ini "kurang ramah" daripada Java agak tidak penting. Lebih buruk lagi, mereka kehilangan poin yang jauh lebih penting tentang pembagian tanggung jawab yang jauh melampaui sintaksis, dan lebih banyak berkaitan dengan bagaimana kode dirancang.
Dalam C ++, pembersihan deterministik ini terjadi pada destruktor objek. Itu berarti objek dapat (dan biasanya harus) dirancang untuk membersihkannya sendiri. Ini menuju esensi desain berorientasi objek - kelas harus dirancang untuk memberikan abstraksi, dan menegakkan invariannya sendiri. Dalam C ++, seseorang melakukan hal itu - dan salah satu invarian yang disediakannya adalah ketika objek dihancurkan, sumber daya yang dikendalikan oleh objek tersebut (semuanya, bukan hanya memori) akan dihancurkan dengan benar.
Java (dan sejenisnya) agak berbeda. Sementara mereka mendukung (semacam) afinalize
yang secara teoritis dapat memberikan kemampuan yang serupa, dukungan tersebut sangat lemah sehingga pada dasarnya tidak dapat digunakan (dan pada kenyataannya, pada dasarnya tidak pernah digunakan).
Akibatnya, alih-alih kelas itu sendiri dapat melakukan pembersihan yang diperlukan, klien kelas perlu mengambil langkah-langkah untuk melakukannya. Jika kita melakukan perbandingan yang cukup singkat, pada pandangan pertama dapat terlihat bahwa perbedaan ini cukup kecil dan Java cukup kompetitif dengan C ++ dalam hal ini. Kita berakhir dengan sesuatu seperti ini. Di C ++, kelasnya terlihat seperti ini:
class Foo {
// ...
public:
void do_whatever() { if (xyz) throw something; }
~Foo() { /* handle cleanup */ }
};
... dan kode klien terlihat seperti ini:
void f() {
Foo f;
f.do_whatever();
// possibly more code that might throw here
}
Di Jawa kita menukar sedikit lebih banyak kode di mana objek digunakan untuk sedikit kurang di kelas. Ini awalnya terlihat seperti trade-off yang lumayan. Pada kenyataannya, itu jauh dari itu, karena dalam kebanyakan kode khas kita hanya mendefinisikan kelas di satu tempat, tetapi kita menggunakannya di banyak tempat. Pendekatan C ++ berarti kita hanya menulis kode itu untuk menangani pembersihan di satu tempat. Pendekatan Java berarti kita harus menulis kode itu untuk menangani pembersihan berulang kali, di banyak tempat - setiap tempat kita menggunakan objek kelas itu.
Singkatnya, pendekatan Java pada dasarnya menjamin bahwa banyak abstraksi yang kami coba berikan adalah "bocor" - setiap dan setiap kelas yang membutuhkan pembersihan deterministik mewajibkan klien kelas untuk mengetahui tentang detail apa yang harus dibersihkan dan bagaimana melakukan pembersihan. , bukannya detail yang disembunyikan di dalam kelas itu sendiri.
Meskipun saya menyebutnya "pendekatan Java" di atas, try
/ finally
dan mekanisme serupa dengan nama lain tidak sepenuhnya terbatas pada Java. Untuk satu contoh yang menonjol, sebagian besar (semua?) Bahasa .NET (misalnya, C #) menyediakan hal yang sama.
Iterasi terbaru dari Java dan C # juga menyediakan titik tengah antara Java "klasik" dan C ++ dalam hal ini. Dalam C #, objek yang ingin mengotomatiskan pembersihannya dapat mengimplementasikan IDisposable
antarmuka, yang menyediakan Dispose
metode yang (setidaknya samar-samar) mirip dengan destruktor C ++. Sementara ini dapat digunakan melalui try
/ finally
seperti di Jawa, C # mengotomatiskan tugas sedikit lebih banyak dengan membuang kelas dalam pelaksanaannya . Yang tersisa untuk programmer klien adalah beban yang lebih rendah dari menulis pernyataan untuk memastikan bahwausing
pernyataan yang memungkinkan Anda menentukan sumber daya yang akan dibuat sebagai ruang lingkup dimasukkan, dan dimusnahkan ketika ruang lingkup keluar. Meskipun masih jauh dari tingkat otomatisasi dan kepastian yang disediakan oleh C ++, ini masih merupakan peningkatan substansial di Jawa. Secara khusus, perancang kelas dapat memusatkan detail tentang caranyaIDisposable
using
IDisposable
antarmuka akan digunakan saat seharusnya. Di Java 7 dan yang lebih baru, namanya telah diubah untuk melindungi yang bersalah, tetapi ide dasarnya pada dasarnya identik.