Seberapa penting menginisialisasi variabel

9

Seberapa pentingkah menginisialisasi variabel?

Apakah inisialisasi yang tepat menghindari kebocoran memori atau memiliki keunggulan kinerja?

Vivek
sumber
14
Itu tergantung pada bahasanya. Dalam beberapa bahasa itu sangat penting untuk mencegah bug, sisanya hanya hal yang baik untuk membantu keterbacaan.
Telastyn
Terima kasih Telastyn untuk masukan Anda. Bisakah Anda meletakkan case di tempat yang penting tergantung pada bahasanya?
Vivek
4
C ++ adalah yang terkenal di sini. Dalam debug, variabel lokal diinisialisasi ke 0 (atau null) oleh kompiler umum, tetapi merupakan sampah acak saat dikompilasi untuk rilis. (Meskipun pengetahuan C ++ saya berasal dari ~ 10 tahun yang lalu sekarang, semuanya mungkin telah berubah)
Telastyn
Ini adalah kasus yang pernah terbakar dua kali malu. Karena saya telah melihat / memiliki bug yang disebabkan oleh variabel yang tidak diinisialisasi, terutama pointer, itu menjadi kebiasaan. Untuk kinerja, biasanya tidak relevan. Untuk kebocoran memori, tidak terlalu masalah.
Mike Dunlavey
1
@ Telastyn lebih buruk dari itu. Perilaku tidak terdefinisi tidak terbatas pada keadaan sampah, apa pun bisa terjadi. Kompilator dapat mengasumsikan bahwa jalur yang membaca variabel yang tidak diinisialisasi tidak dapat dijangkau, dan menghilangkan efek "tidak terkait" yang terjadi di sepanjang jalan.
Caleth

Jawaban:

7

Variabel yang tidak diinisialisasi membuat program menjadi non-deterministik. Setiap kali program berjalan, ia mungkin berperilaku berbeda. Perubahan yang tidak terkait dengan lingkungan operasi, waktu hari, fase bulan dan permutasi seperti itu mempengaruhi bagaimana dan kapan daemon ini terwujud. Program dapat berjalan jutaan kali sebelum cacat hadir, mereka dapat melakukannya setiap waktu, atau menjalankan jutaan lainnya. Banyak masalah diletakkan ke "gangguan" dan diabaikan, atau laporan cacat dari pelanggan ditutup sebagai "Tidak Dapat Diproduksi". Seberapa sering Anda me-reboot mesin untuk 'memperbaiki' masalah? Seberapa sering Anda berkata kepada pelanggan, "Belum pernah melihat itu terjadi, beri tahu saya jika Anda melihatnya lagi" - berharap (mengetahui) dengan baik mereka tidak akan!

Karena reproduksi cacat mungkin nyaris tidak mungkin dalam lingkungan pengujian, maka hampir tidak mungkin untuk menemukan dan memperbaikinya.

Butuh waktu bertahun-tahun bagi bug untuk muncul ke permukaan, biasanya dalam kode yang dianggap andal dan stabil. Cacat dianggap dalam kode yang lebih baru - melacaknya bisa memakan waktu lebih lama secara signifikan. Perubahan pada kompiler, sakelar kompiler, bahkan menambahkan sebaris kode dapat mengubah perilaku.

Variabel inisialisasi memiliki keunggulan kinerja yang sangat besar, bukan hanya karena program yang berfungsi dengan benar lebih cepat daripada yang tidak, tetapi pengembang menghabiskan lebih sedikit waktu untuk menemukan dan memperbaiki cacat yang seharusnya tidak ada dan lebih banyak waktu melakukan pekerjaan "nyata".

Keuntungan signifikan lain dari variabel inisialisasi adalah pembuat kode asli harus memutuskan apa yang harus diinisialisasi. Ini tidak selalu merupakan latihan yang sepele, dan ketika tidak sepele, bisa menjadi indikasi dari desain yang buruk.

Kebocoran memori adalah masalah yang berbeda, tetapi inisialisasi yang tepat tidak hanya dapat membantu dalam mencegahnya, itu juga dapat membantu dalam mendeteksi mereka dan menemukan sumber - sangat tergantung pada bahasa dan itu benar-benar pertanyaan terpisah yang layak untuk dijelajahi lebih lanjut daripada yang bisa saya berikan dalam jawaban ini.

Sunting: Dalam beberapa bahasa (misalnya C #) tidak mungkin untuk menggunakan variabel yang tidak diinisialisasi, karena program tidak akan mengkompilasi, atau melaporkan kesalahan ketika dieksekusi, jika dilakukan. Namun, banyak bahasa dengan karakteristik ini memiliki antarmuka untuk kode yang berpotensi tidak aman, jadi harus berhati-hati saat menggunakan antarmuka seperti itu untuk memperkenalkan variabel yang tidak diinisialisasi.

mattnz
sumber
6
Banyak bahasa pemrograman secara otomatis mengatur variabel mereka ke beberapa nilai yang telah ditentukan, sehingga sebagian besar dari apa yang Anda katakan di sini tidak berlaku untuk bahasa-bahasa tersebut.
Robert Harvey
2
Hanya untuk mengulangi apa yang dikatakan @RobertHarvey, semua ini tidak berlaku untuk C #. Tidak ada keuntungan kinerja untuk menginisialisasi variabel Anda ketika Anda mendeklarasikannya, dan tidak mungkin untuk menggunakan variabel yang tidak diinisialisasi, sehingga Anda tidak dapat menyalahkan bug yang tidak dapat diproduksi atas hal itu. (Ini adalah mungkin untuk menggunakan lapangan kelas diinisiasi, tapi itu akan set ke nilai default dan menghasilkan peringatan dalam kasus itu)
Bobson
4
@ mattnz - Intinya adalah bahwa untuk bahasa yang berperilaku seperti C # (atau Java), beberapa saran ini menyesatkan atau salah. Sebagai pertanyaan agnostik bahasa, harus memiliki respon agnostik bahasa, yang berarti menangani bahasa yang melakukan pegangan diinisialisasi variabel aman serta mereka yang tidak.
Bobson
1
Saya juga menambahkan bahwa masalah variabel yang tidak diinisialisasi tidak sulit ditemukan karena setiap kompiler / penganalisa statis yang layak akan memperingatkan mereka
jk.
1
Untuk Java (dan C # mungkin) menginisialisasi prematur penduduk lokal tidak perlu dan bisa dibilang mengarah ke lebih banyak bug. Misalnya, menetapkan variabel ke nol sebelum menetapkannya secara kondisional mengalahkan kemampuan kompiler untuk memberi tahu Anda bahwa salah satu jalur melalui kode tidak dapat menghasilkan variabel yang ditugaskan.
JimmyJames
7

Menginisialisasi variabel seperti yang ditunjukkan Telastyn dapat mencegah bug. Jika variabel adalah tipe referensi, menginisialisasi itu dapat mencegah kesalahan referensi nol di telepon.

Variabel jenis apa pun yang memiliki standar non null akan mengambil sebagian memori untuk menyimpan nilai default.

Kevin
sumber
6

Mencoba menggunakan variabel yang tidak diinisialisasi selalu merupakan bug, jadi masuk akal untuk meminimalkan kemungkinan bug itu terjadi.

Mungkin bahasa pemrograman pendekatan yang paling umum diambil untuk mengurangi masalah adalah dengan secara otomatis menginisialisasi ke nilai default, jadi setidaknya jika Anda lupa menginisialisasi variabel, itu akan menjadi sesuatu seperti 0bukan sesuatu seperti 0x16615c4b.

Ini memecahkan sebagian besar bug, jika Anda membutuhkan variabel yang diinisialisasi ke nol. Namun, menggunakan variabel yang diinisialisasi ke nilai yang salah sama buruknya dengan menggunakan variabel yang tidak diinisialisasi sama sekali. Bahkan, kadang-kadang bisa lebih buruk, karena kesalahan bisa lebih halus dan sulit dideteksi.

Bahasa pemrograman fungsional memecahkan masalah ini dengan tidak hanya melarang nilai yang tidak diinisialisasi, tetapi dengan melarang penugasan kembali sama sekali. Itu menghilangkan masalah dan ternyata menjadi tidak separah yang Anda pikirkan. Bahkan dalam bahasa non-fungsional, jika Anda menunggu untuk mendeklarasikan variabel hingga Anda memiliki nilai yang benar untuk menginisialisasi, kode Anda cenderung jauh lebih kuat.

Sejauh kinerja berjalan, itu mungkin diabaikan. Paling buruk dengan variabel tidak diinisialisasi, Anda memiliki satu tugas tambahan, dan mengikat beberapa memori lebih lama dari yang diperlukan. Kompiler yang baik dapat mengoptimalkan perbedaan dalam banyak kasus.

Kebocoran memori sama sekali tidak terkait, meskipun variabel yang diinisialisasi dengan benar cenderung berada dalam ruang lingkup untuk periode waktu yang lebih pendek, dan karena itu mungkin agak kurang mungkin bagi seorang programmer untuk secara tidak sengaja bocor.

Karl Bielefeldt
sumber
Selalu? Maksud Anda "selalu" seperti dalam "Bagaimana pesan Valgrind tetap membuat OpenSSL di sebelah tidak berguna" marc.info/?t=114651088900003&r=1&w=2 ? Atau maksud Anda yang lain, yang "hampir selalu"?
JensG
1
Saya dapat memikirkan tiga bahasa yang memungkinkan variabel tidak diinisialisasi tanpa kesalahan, salah satunya menggunakan itu untuk tujuan linguistik.
DougM
Saya akan tertarik pada spesifikasinya. Saya akan curiga dalam kasus-kasus variabel tidak benar-benar diinisialisasi, tetapi diinisialisasi dengan cara selain langsung oleh programmer di situs deklarasi. Atau mereka ditugaskan dengan cara tidak langsung sebelum dereferensi.
Karl Bielefeldt
5

Inisialisasi, menyiratkan bahwa nilai awal penting. Jika nilai awal penting, maka ya, jelas Anda harus memastikan itu diinisialisasi. Jika tidak masalah, itu berarti akan diinisialisasi nanti.

Inisialisasi yang tidak perlu menyebabkan siklus CPU terbuang. Meskipun siklus yang terbuang ini mungkin tidak penting dalam program tertentu, dalam program lain, setiap siklus tunggal penting karena kecepatan menjadi perhatian utama. Jadi, sangat penting untuk memahami apa tujuan kinerja seseorang dan apakah variabel perlu diinisialisasi atau tidak.

Kebocoran memori adalah masalah yang sangat berbeda yang biasanya melibatkan fungsi pengalokasi memori untuk mengeluarkan dan kemudian mendaur ulang blok memori. Pikirkan kantor pos. Anda pergi dan meminta kotak surat. Mereka memberimu satu. Anda meminta yang lain. Mereka memberi Anda satu lagi. Aturannya adalah bahwa ketika Anda selesai menggunakan kotak surat, Anda harus mengembalikannya. Jika Anda lupa mengembalikannya, mereka masih berpikir Anda memilikinya, dan kotak itu tidak dapat digunakan kembali oleh orang lain. Jadi ada sepotong memori yang diikat dan tidak digunakan, dan inilah yang disebut dengan kebocoran memori. Jika Anda terus meminta kotak di beberapa titik Anda akan kehabisan memori. Saya terlalu menyederhanakan ini, tetapi ini adalah ide dasar.

Pandangan elips
sumber
-1 Anda mendefinisikan ulang apa arti inisialisasi dalam konteks ini.
Pieter B
@Pieter B, saya tidak mengerti komentar Anda. Tolong, jika Anda mau, katakan bagaimana saya, "mendefinisikan kembali apa arti inisialisasi dalam konteks ini". Terima kasih
Tampilan elips
Baca Anda sendiri kalimat, itu penalaran melingkar: "Inisialisasi, menyiratkan bahwa nilai awal penting. Jika nilai awal penting, maka ya, Anda harus memastikan itu diinisialisasi. Jika tidak masalah, itu menyiratkan bahwa ia akan mendapatkan diinisialisasi nanti. "
Pieter B
@Pieter B, Beberapa orang menginisialisasi sebagai aturan umum alih-alih karena alasan terprogram, yaitu mereka menginisialisasi apakah nilai awal itu penting atau tidak. Bukankah ini jantung dari OQ: Seberapa pentingkah menginisialisasi variabel? Lagi pula, Anda sudah terpilih di sini.
Pemandangan elips
2

Seperti kata orang lain, itu tergantung pada bahasa. Tapi saya akan menunjukkan ide Java (dan Java Efektif) saya tentang menginisialisasi variabel. Ini harus dapat digunakan untuk banyak bahasa tingkat tinggi lainnya.

Konstanta dan variabel kelas

Variabel kelas - ditandai dengan staticdi Jawa - seperti konstanta. Variabel-variabel ini biasanya harus final dan diinisialisasi langsung setelah definisi menggunakan =atau dari dalam blok initializer kelas static { // initialize here }.

Bidang

Seperti di banyak level yang lebih tinggi dan bidang bahasa scripting akan secara otomatis diberikan nilai default. Untuk angka dan charini akan menjadi nilai nol. Untuk Strings dan objek lainnya null. Sekarang nullberbahaya dan harus digunakan dengan hemat. Jadi bidang ini harus ditetapkan ke nilai yang valid sesegera mungkin. Konstruktor biasanya merupakan tempat yang sempurna untuk ini. Untuk memastikan bahwa variabel ditetapkan selama konstruktor, dan tidak berubah setelahnya, Anda dapat menandainya dengan finalkata kunci.

Coba dan tahan keinginan untuk menggunakan nullsemacam bendera atau nilai khusus. Lebih baik misalnya memasukkan bidang tertentu untuk menahan keadaan. Bidang dengan nama stateyang menggunakan nilai-nilai Stateenumerasi akan menjadi pilihan yang baik.

Parameter metode

Karena perubahan nilai parameter (baik itu referensi ke objek atau tipe dasar seperti bilangan bulat dll) tidak akan terlihat oleh pemanggil, parameter harus ditandai sebagai final. Ini berarti bahwa nilai-nilai variabel itu sendiri tidak dapat diubah. Perhatikan bahwa nilai bisa berubah contoh objek dapat diubah, referensi tidak dapat diubah ke titik ke objek yang berbeda atau nullsekalipun.

Variabel lokal

Variabel lokal tidak diinisialisasi secara otomatis; mereka perlu diinisialisasi sebelum nilainya dapat digunakan. Salah satu metode untuk memastikan bahwa variabel Anda diinisialisasi adalah menginisialisasi mereka ke beberapa jenis nilai default secara langsung. Namun ini adalah sesuatu yang tidak boleh Anda lakukan. Sebagian besar waktu, nilai default bukan nilai yang Anda harapkan.

Adalah jauh lebih baik untuk hanya mendefinisikan variabel tepat di mana Anda memerlukan variabel. Jika variabel hanya mengambil nilai tunggal (yang berlaku untuk sebagian besar variabel dalam kode yang baik) maka Anda dapat menandai variabel tersebut final. Ini memastikan bahwa variabel lokal ditetapkan tepat sekali, bukan nol kali atau dua kali. Sebuah contoh:

public static doMethod(final int x) {
    final int y; // no assignment yet, it's final so it *must* be assigned
    if (x < 0) {
        y = 0;
    } else if (x > 0) {
        y = x;
    } else {
        // do nothing <- error, y not assigned if x = 0
        // throwing an exception here is acceptable though
    }
}

Perhatikan bahwa banyak bahasa akan memperingatkan Anda jika variabel tetap tidak diinisialisasi sebelum digunakan. Periksa spesifikasi bahasa dan forum untuk melihat apakah Anda tidak perlu khawatir.

Maarten Bodewes
sumber
1

Tidak ada masalah dengan variabel inisialisasi.

Masalahnya hanya ketika Anda membaca variabel yang belum ditulis.

Bergantung pada kompiler dan / atau pada jenis variabel, inisialisasi dilakukan pada saat startup aplikasi. Atau tidak.

Ini adalah penggunaan umum untuk tidak bergantung pada inisialisasi otomatis.

mouviciel
sumber
0

Menginisialisasi variabel (secara implisit atau eksplisit) sangat penting. Tidak menginisialisasi variabel selalu merupakan kesalahan (mereka mungkin diinisialisasi secara implisit. Namun, lihat di bawah). Compliers modern seperti kompiler C # (sebagai contoh) memperlakukan ini sebagai kesalahan dan tidak akan membiarkan Anda mengeksekusi kode. Variabel tidak diinisialisasi sama sekali tidak berguna dan berbahaya. Kecuali jika Anda membuat generator angka acak, Anda berharap dari sepotong kode untuk menghasilkan hasil deterministik dan direproduksi. Ini hanya dapat dicapai jika Anda mulai bekerja dengan variabel yang diinisialisasi.

Pertanyaan yang sangat menarik adalah apakah suatu variabel diinisialisasi secara otomatis atau apakah Anda harus melakukannya secara manual. Itu tergantung pada bahasa yang digunakan. Dalam C # misalnya, bidang, yaitu "variabel" di tingkat kelas, selalu secara otomatis diinisialisasi ke nilai default untuk tipe variabel itu default(T). Nilai ini sesuai dengan pola bit yang terdiri dari semua nol. Ini adalah bagian dari spesifikasi bahasa dan bukan hanya detail teknis dari implementasi bahasa. Karena itu Anda dapat dengan aman mengandalkannya. Aman untuk tidak menginisialisasi variabel secara eksplisit jika (dan hanya jika) spesifikasi bahasa menyatakan bahwa itu diinisialisasi secara implisit.Jika Anda menginginkan nilai lain, Anda harus menginisialisasi variabel secara eksplisit. Namun; dalam C # variabel lokal, yaitu variabel yang dideklarasikan dalam metode, tidak diinisialisasi secara otomatis dan Anda harus selalu menginisialisasi variabel secara eksplisit.

Olivier Jacot-Descombes
sumber
2
ini bukan pertanyaan khusus C #.
DougM
@DougM: Saya tahu. Ini bukan jawaban khusus C #, saya hanya mengambil C # sebagai contoh.
Olivier Jacot-Descombes
Tidak semua bahasa memerlukan variabel yang diinisialisasi secara eksplisit. Pernyataan "tidak menginisialisasi selalu merupakan kesalahan" salah, dan tidak menambahkan kejelasan pertanyaan apa pun. Anda mungkin ingin merevisi jawaban Anda.
DougM
@DougM: Sudahkah Anda mengawasi kalimat saya "Pertanyaan yang sangat menarik adalah apakah suatu variabel diinisialisasi secara otomatis atau apakah Anda harus melakukannya secara manual."?
Olivier Jacot-Descombes
maksudmu yang terkubur di tengah paragraf? Iya. Anda seharusnya membuatnya lebih menonjol, dan menambahkan kualifikasi untuk klaim "selalu" Anda.
DougM