Kapan & mengapa pointer mulai dianggap berisiko?

18

Tampaknya ada pergeseran bertahap dalam berpikir tentang penggunaan pointer dalam bahasa pemrograman sehingga menjadi diterima secara umum bahwa pointer dianggap berisiko (jika tidak langsung "jahat" atau peningkatan yang serupa).

Apa perkembangan historis untuk pergeseran pemikiran ini? Adakah acara khusus, seminar, penelitian, atau perkembangan lainnya?

Sebagai contoh, tampilan dangkal pada transisi dari C ke C ++ ke Java tampaknya menunjukkan tren untuk melengkapi dan kemudian sepenuhnya mengganti pointer dengan referensi. Namun rantai kejadian sebenarnya mungkin jauh lebih halus & kompleks daripada ini, dan tidak begitu berurutan. Fitur-fitur yang membuatnya menjadi bahasa utama tersebut mungkin berasal dari tempat lain, mungkin jauh sebelumnya.

Catatan: Saya tidak bertanya tentang manfaat sebenarnya dari pointer vs referensi vs sesuatu yang lain. Fokus saya adalah pada alasan untuk perubahan yang tampak ini.

DaveInCaz
sumber
1
Itu karena penurunan pendidikan Seni Liberal. Orang tidak lagi dapat memahami Referensi Tidak Langsung, salah satu ide paling mendasar dalam teknologi komputasi, termasuk dalam semua CPU.
10
Pointer yang berisiko. Menurut Anda mengapa ada pergeseran pemikiran? Ada peningkatan dalam fitur bahasa dan perangkat keras yang memungkinkan penulisan perangkat lunak tanpa petunjuk, meskipun bukan tanpa penalti kinerja.
Berhentilah melukai Monica
4
@ DaveInCaz Sejauh yang saya tahu bahwa pengembangan spesifik adalah penemuan pointer.
Berhentilah melukai Monica
5
@nocomprende: apa yang baru saja Anda tulis bukanlah fakta atau bukti, hanya pendapat. Ada jauh lebih sedikit programmer pada tahun 1970, Anda tidak memiliki bukti populasi saat ini lebih baik atau lebih buruk di "referensi tidak langsung".
whatsisname
3
Pointer selalu dianggap berisiko, sejak hari pertama. Itu hanya kompromi untuk memindahkan mereka dari bahasa assembly ke bahasa tingkat yang lebih tinggi.
Frank Hileman

Jawaban:

21

Alasannya adalah pengembangan alternatif untuk pointer.

Di bawah tenda, setiap pointer / referensi / dll sedang diimplementasikan sebagai integer yang berisi alamat memori (alias pointer). Ketika C keluar, fungsi ini diekspos sebagai pointer. Ini berarti bahwa apa pun yang dapat dilakukan perangkat keras yang mendasar untuk mengatasi memori dapat dilakukan dengan pointer.

Ini selalu "berbahaya," tetapi bahaya itu relatif. Saat Anda membuat program 1000 garis, atau ketika Anda memiliki prosedur kualitas perangkat lunak tingkat IBM, bahaya ini dapat dengan mudah diatasi. Namun, tidak semua perangkat lunak dikembangkan dengan cara itu. Dengan demikian, keinginan untuk struktur yang lebih sederhana muncul.

Jika Anda berpikir tentang itu, int&dan int* constbenar-benar memiliki tingkat keamanan yang sama, tetapi satu memiliki sintaks yang jauh lebih baik daripada yang lain. int&bisa juga lebih efisien karena bisa merujuk ke int yang disimpan dalam register (anakronisme: ini benar di masa lalu, tetapi kompiler modern sangat baik dalam mengoptimalkan sehingga Anda dapat memiliki pointer ke integer dalam register, selama Anda tidak pernah menggunakan salah satu fitur yang memerlukan alamat aktual, seperti ++)

Saat kami pindah ke Jawa , kami pindah ke bahasa yang memberikan jaminan keamanan. C dan C ++ tidak tersedia. Java menjamin bahwa hanya operasi hukum yang dapat dijalankan. Untuk melakukan ini, java menghilangkan pointer sepenuhnya. Apa yang mereka temukan adalah bahwa sebagian besar operasi pointer / referensi dilakukan dalam kode nyata adalah hal-hal yang lebih dari cukup untuk referensi. Hanya dalam beberapa kasus (seperti iterasi cepat melalui array) yang benar-benar diperlukan pointer. Dalam kasus tersebut, java mengambil hit runtime untuk menghindari menggunakannya.

Langkah itu tidak monoton. C # diperkenalkan kembali pointer, meskipun dalam bentuk yang sangat terbatas. Mereka ditandai sebagai " tidak aman ," yang berarti mereka tidak dapat digunakan oleh kode yang tidak dipercaya. Mereka juga memiliki aturan eksplisit tentang apa yang mereka bisa dan tidak bisa tunjukkan (misalnya, itu hanya tidak valid untuk menambah pointer melewati akhir array). Namun, mereka menemukan ada beberapa kasus di mana kinerja tinggi dari pointer diperlukan, jadi mereka memasukkannya kembali.

Yang juga menarik adalah bahasa fungsional, yang tidak memiliki konsep seperti itu sama sekali, tapi itu diskusi yang sangat berbeda.

Cort Ammon - Pulihkan Monica
sumber
3
Saya tidak yakin benar untuk mengatakan bahwa Java tidak memiliki petunjuk. Saya tidak ingin terlibat dalam perdebatan panjang tentang apa itu dan bukan pointer tetapi JLS mengatakan bahwa "nilai referensi adalah sebuah pointer". Tidak ada akses langsung atau modifikasi pointer yang diizinkan. Ini bukan hanya untuk keamanan juga, menjaga orang keluar dari bisnis melacak di mana suatu objek setiap saat bermanfaat untuk GC.
JimmyJames
6
@ JimmyJames Benar. Untuk keperluan jawaban ini, garis pemisah antara pointer dan bukan-pointer adalah apakah itu mendukung operasi aritmatika pointer, yang biasanya tidak didukung oleh referensi.
Cort Ammon - Reinstate Monica
8
@ JimmyJames Saya setuju dengan pernyataan Cort bahwa pointer adalah sesuatu yang dapat Anda lakukan operasi aritmatika, sedangkan referensi tidak. Mekanisme aktual yang mengimplementasikan referensi dalam bahasa seperti Java adalah detail implementasi.
Robert Harvey
3
Secara umum, C dan C ++ telah secara sukarela menerima keanggotaan ke dalam klub berbahaya ini dengan mengizinkan banyak "perilaku tidak terdefinisi" ke dalam spesifikasi.
rwong
2
By the way, ada yang CPU, yang membedakan antara pointer dan angka. Misalnya, CPU CISC 48-bit asli di IBM AS / 400 melakukan itu. Dan pada kenyataannya, ada lapisan abstraksi di bawah OS, yang berarti bahwa tidak hanya CPU membedakan antara angka dan pointer dan melarang aritmatika pada pointer, tetapi OS itu sendiri bahkan tidak tahu tentang pointer sama sekali dan juga tidak ada bahasa . Menariknya, ini membuat AS / 400 satu sistem asli, di mana penulisan ulang kode dari bahasa scripting tingkat tinggi di C membuatnya urutan besarnya lebih lambat .
Jörg W Mittag
10

Beberapa jenis tipuan diperlukan untuk program yang kompleks (misalnya struktur data rekursif atau berukuran variabel). Namun, tidak perlu menerapkan tipuan ini melalui pointer.

Mayoritas bahasa pemrograman tingkat tinggi (yaitu bukan Majelis) cukup aman-memori dan melarang akses pointer tidak terbatas. Keluarga C adalah yang aneh di sini.

C berevolusi dari B yang merupakan abstraksi yang sangat tipis pada perakitan mentah. B memiliki satu tipe: kata. Kata tersebut dapat digunakan sebagai integer atau sebagai pointer. Keduanya setara ketika seluruh memori dipandang sebagai array yang berdekatan. C menyimpan pendekatan yang agak fleksibel ini dan terus mendukung aritmatika pointer yang secara inheren tidak aman. Seluruh sistem tipe C lebih merupakan sebuah renungan. Fleksibilitas terhadap akses memori ini menjadikan C sangat cocok untuk tujuan utamanya: membuat prototip sistem operasi Unix. Tentu saja Unix dan C ternyata cukup populer, sehingga C juga digunakan dalam aplikasi di mana pendekatan tingkat rendah terhadap memori ini tidak terlalu dibutuhkan.

Jika kita melihat bahasa pemrograman yang datang sebelum C (misalnya Fortran, dialek Algol termasuk Pascal, Cobol, Lisp, ...) beberapa dari mereka mendukung pointer mirip-C. Khususnya, konsep penunjuk nol diciptakan untuk Algol W pada tahun 1965. Tetapi tidak satu pun dari bahasa tersebut yang mencoba menjadi bahasa sistem abstraksi rendah seperti C, efisien, dan Fortran dimaksudkan untuk komputasi ilmiah, Algol mengembangkan beberapa konsep yang cukup maju, Lisp mengembangkan lebih dari proyek penelitian daripada bahasa tingkat industri, dan Cobol berfokus pada aplikasi bisnis.

Pengumpulan sampah sudah ada sejak akhir 50-an, yaitu jauh sebelum C (awal 70-an). GC membutuhkan keamanan memori agar berfungsi dengan benar. Bahasa sebelum dan sesudah C menggunakan GC sebagai fitur normal. Tentu saja itu membuat bahasa jauh lebih rumit dan mungkin lebih lambat, yang terutama terlihat pada saat mainframe. Bahasa-bahasa GC cenderung berorientasi pada penelitian (misalnya Lisp, Simula, ML) dan / atau membutuhkan workstation yang kuat (mis. Smalltalk).

Dengan komputer yang lebih kecil, komputer yang lebih kuat pada umumnya dan bahasa GC secara khusus menjadi lebih populer. Untuk aplikasi non-real time (dan kadang-kadang bahkan saat itu) GC sekarang merupakan pendekatan yang disukai. Tetapi algoritma GC juga telah menjadi subjek penelitian yang intens. Sebagai alternatif, keamanan memori yang lebih baik tanpa GC juga telah dikembangkan lebih lanjut, terutama dalam tiga dekade terakhir: inovasi penting adalah RAII dan smart pointer di C ++ dan sistem seumur hidup / pemeriksa pinjaman Rust.

Java tidak berinovasi dengan menjadi bahasa pemrograman memori-aman: pada dasarnya mengambil semantik dari bahasa Smalltalk GCed, memori aman dan menggabungkannya dengan sintaks dan mengetik statis C ++. Itu kemudian dipasarkan sebagai C / C ++ yang lebih baik, lebih sederhana. Tapi itu hanya dangkal keturunan C ++. Kurangnya pointer Java berutang lebih banyak pada model objek Smalltalk daripada penolakan model data C ++.

Jadi bahasa "modern" seperti Java, Ruby, dan C # tidak boleh diartikan sebagai mengatasi masalah pointer mentah seperti di C, tetapi harus dilihat sebagai menggambar dari banyak tradisi - termasuk C, tetapi juga dari bahasa yang lebih aman seperti Smalltalk, Simula, atau Lisp.

amon
sumber
4

Dalam pengalaman saya, pointer telah SELALU menjadi konsep yang menantang bagi banyak orang. Pada tahun 1970, universitas tempat saya kuliah memiliki Burroughs B5500, dan kami menggunakan Extended Algol untuk proyek pemrograman kami. Arsitektur perangkat keras didasarkan pada deskriptor dan beberapa kode di bagian atas kata-kata data. Ini secara eksplisit dirancang untuk membiarkan array menggunakan pointer tanpa diizinkan berjalan keluar dari ujung.

Kami melakukan diskusi kelas yang bersemangat tentang referensi nama vs nilai dan bagaimana array B5500 bekerja. Beberapa dari kami langsung mendapat penjelasan. Yang lain tidak.

Belakangan, agak mengejutkan bahwa perangkat keras itu tidak melindungi saya dari petunjuk pelarian - terutama dalam bahasa assembly. Pada pekerjaan pertama saya setelah lulus, saya membantu memperbaiki masalah dalam sistem operasi. Seringkali satu-satunya dokumentasi yang kami miliki adalah tempat sampah cetak. Saya mengembangkan ketrampilan untuk menemukan sumber pointer melarikan diri di dump memori, jadi semua orang memberikan dump "mustahil" kepada saya untuk mencari tahu. Lebih banyak masalah yang kami miliki disebabkan oleh kesalahan pointer daripada oleh jenis kesalahan lainnya.

Banyak orang yang pernah bekerja sama dengan saya mulai menulis FORTRAN, kemudian pindah ke C, menulis C yang sangat mirip FORTRAN, dan menghindari petunjuk. Karena mereka tidak pernah menginternalisasi pointer dan referensi, Java menimbulkan masalah. Seringkali, sulit untuk memahami bagi programmer FORTRAN bagaimana tugas Obyek benar-benar bekerja.

Bahasa modern telah membuatnya jauh lebih mudah untuk melakukan hal-hal yang membutuhkan pointer "di bawah tenda" sambil menjaga kita aman dari kesalahan ketik dan kesalahan lainnya.

Valerie Griffin
sumber