Setiap variabel di C++ memiliki wilayah keabsahan nama, yaitu lingkup (scope), serta lama hidupnya di memori, yaitu durasi penyimpanan (storage duration). Keduanya ditentukan oleh tempat deklarasi dan kata kunci yang menyertainya, sehingga memahaminya penting untuk mencegah error yang sulit dilacak. Topik ini membahas variabel local dan global, kata kunci static, serta tiga durasi penyimpanan, yaitu automatic, dynamic, dan static.
Lingkup: wilayah keabsahan nama#
Lingkup menentukan dari mana sebuah nama dapat disebut. Variabel yang dideklarasikan di dalam blok kurung kurawal, misalnya di dalam badan fungsi, berlaku dari titik deklarasinya sampai akhir blok tersebut. Variabel yang dideklarasikan di luar semua fungsi berlaku sampai akhir berkas dan dinamakan variabel global.
#include <iostream>
int nilai = 5;
void tampilkan() {
std::cout << "Dari fungsi: " << nilai << '\n';
}
int main() {
tampilkan();
int nilai = 10;
std::cout << "Dari main: " << nilai << '\n';
return 0;
}Dari fungsi: 5
Dari main: 10Fungsi tampilkan membaca nilai global yang bernilai 5, sedangkan main menggunakan deklarasi lokalnya sendiri, yaitu nilai yang bernilai 10. Peristiwa ini disebut shadowing, yakni nama lokal membayangi nama yang sama pada lingkup luar. Compiler tidak memberi error atas shadowing, sehingga nama-nama berbeda sebaiknya dipakai agar maksud kode tetap jelas.
Variabel global memang nyaman karena dapat diakses dari mana pun, tetapi akses bebas itu membuat aliran data program sulit dinalar seiring bertambahnya kode. Batasi variabel global untuk data yang benar-benar bersifat umum, dan kirimkan data lain melalui parameter fungsi.
Kata kunci static pada variabel global memiliki peran yang berbeda, yaitu membatasi visibilitasnya hanya pada unit penerjemahan tempat deklarasinya berada. Berkas lain tidak dapat menyebut variabel tersebut meskipun membacanya lewat deklarasi extern, dan dua berkas boleh masing-masing memiliki variabel static dengan nama sama tanpa bentrok. Fasilitas ini berguna untuk data kerja internal berkas yang tidak perlu dikenali bagian lain program.
Masa hidup dan durasi penyimpanan#
Durasi penyimpanan menentukan kapan memori sebuah objek diciptakan dan dimusnahkan, dan sifat ini tidak selalu sejalan dengan lingkupnya. Tabel berikut merangkum tiga durasi yang dipakai program C++ pada tahap ini.
| Durasi penyimpanan | Ciri khas | Contoh |
|---|---|---|
| Automatic | Diciptakan saat masuk blok, dimusnahkan saat keluar blok | Variabel lokal biasa |
| Static | Diciptakan sekali sebelum main berjalan, hidup sampai program berakhir | Variabel global, variabel static lokal |
| Dynamic | Diciptakan dan dimusnahkan dengan new dan delete | Alokasi lewat pointer |
Variabel static di dalam fungsi memperlihatkan keterpisahan lingkup dari durasi penyimpanan. Ia hanya terlihat di dalam fungsi yang mendeklarasikannya. Meskipun demikian, nilainya bertahan antarpemanggilan karena memorinya tidak dimusnahkan saat fungsi berakhir.
#include <iostream>
int berikutnya() {
static int urutan = 1;
return urutan++;
}
int main() {
std::cout << berikutnya() << ' ';
std::cout << berikutnya() << ' ';
std::cout << berikutnya() << '\n';
return 0;
}1 2 3Inisialisasi static int urutan = 1 hanya dijalankan satu kali, sedangkan setiap pemanggilan berikutnya mengembalikan nilai yang tersimpan lalu menaikkannya, sehingga keluarannya 1, 2, lalu 3. Tanpa static, setiap pemanggilan akan mengulang angka 1 karena urutan akan dibuat ulang setiap kali. Pola ini berguna untuk penghitung, nomor urut, dan cache kecil di dalam fungsi.
Penyimpanan dynamic#
Durasi dynamic menyerahkan kendali masa hidup kepada penulis program melalui operator new dan delete. Objek yang dialokasikan dengan new tidak terikat blok mana pun, sehingga hidup sampai delete dipanggil atau sampai program berakhir tanpa pembebasan.
#include <iostream>
int main() {
int* nilai = new int(42);
std::cout << "Nilai dinamis: " << *nilai << '\n';
delete nilai;
return 0;
}Nilai dinamis: 42Operator new int(42) menyediakan memori untuk satu int, mengisinya dengan 42, dan mengembalikan alamatnya, yang kemudian disimpan oleh pointer nilai. Pemanggilan delete nilai mengembalikan memori itu ke sistem, dan pemakaian pointer setelahnya berisiko menjadi use-after-free. Kendali penuh ini adalah sumber utama bug memori, sehingga pembahasan lengkapnya diberi modul tersendiri pada bagian pointer dan memori dinamis.
Apabila pemberian memori gagal, operator new melempar exception berupa std::bad_alloc alih-alih mengembalikan null. Exception adalah mekanisme pelaporan kegagalan yang harus ditangkap oleh kode penanganan, dan program yang tidak menangkapnya berhenti. Perilaku ini berbeda dari fungsi alokasi C yang mengembalikan pointer null saat gagal. Bentuk new (std::nothrow) menyerahkan kegagalan kepada pemanggil tanpa exception, bila gaya penanganan itu memang diperlukan. Ukuran alokasi juga perlu dipertimbangkan lebih dahulu, karena memori yang diperoleh tetap dipegang sampai delete dipanggil.
Kesalahan umum#
Mengembalikan alamat atau reference ke variabel lokal adalah kesalahan berbahaya. Variabel berdurasi automatic dimusnahkan saat fungsi berakhir, sehingga alamat yang dikembalikan menunjuk memori yang sudah tidak sah dan perilakunya tidak terdefinisi. Kembalikan nilai tersebut dengan pass by value, atau pindahkan penyimpanannya ke durasi static atau dynamic yang memang dirancang untuk hidup lebih lama.
Lupa memanggil delete atas hasil new menyebabkan kebocoran memori (memory leak), yaitu memori yang tidak pernah dikembalikan selama program berjalan. Kebocoran tunggal jarang terasa, tetapi alokasi yang berulang tanpa pembebasan menghabiskan memori secara perlahan. Kaidah yang mencegah kebocoran semacam ini dibahas pada topik new dan delete beserta smart pointer.
Variabel lokal berdurasi automatic yang dibaca tanpa inisialisasi berisi nilai sampah. Nilai tersebut berubah-ubah antarjalan program dan tidak ada yang menjaminnya nol, sehingga setiap deklarasi sebaiknya langsung diberi nilai awal. Compiler modern umumnya memberi peringatan atas pemakaian variabel yang belum diinisialisasi, dan peringatan itu layak ditindaklanjuti. Opsi peringatan compiler yang diaktifkan sejak awal proyek membuat temuan semacam ini muncul sebelum kode dipakai.
Ringkasan#
- Lingkup menentukan dari mana nama dapat disebut, dan deklarasi lokal dapat membayangi nama yang sama pada lingkup luar.
- Durasi penyimpanan automatic terikat blok, static hidup sepanjang program, sedangkan dynamic dikendalikan lewat
newdandelete. - Variabel
staticlokal menggabungkan lingkup terbatas dengan masa hidup panjang, sehingga nilainya bertahan antarpemanggilan.
Referensi#
- Storage duration — cppreference.com — Definisi resmi automatic, static, dynamic, dan thread storage duration.
- Introduction to local scope — LearnCpp — Lingkup blok, shadowing, dan masa hidup variabel lokal.
- Static local variables — LearnCpp — Variabel static di dalam fungsi dan durasi penyimpanannya.
- Introduction to global variables — LearnCpp — Variabel global, lingkup berkas, dan pertimbangan pemakaiannya.