Dalam C, Anda akan sering / kadang-kadang (karena gaya) menggunakan static
variabel lingkup file di mana Anda akan menggunakan variabel anggota kelas pribadi di C ++. Saat melakukan penskalaan ke program multithreaded, cukup menambahkan thread_local
C11 atau ekstensi yang didukung lama __thread
cocok. Saya tahu Anda bisa melakukan hal yang persis sama dalam C sebagai C ++ dengan meletakkan segala sesuatu di dalam struct
dan membuat satu set fungsi yang mengambil pointer ke itu struct
sebagai argumen pertama. Beberapa perpustakaan melakukan ini secara ekstensif. Tapi gaya pribadi saya adalah menjaga struct
sekecil mungkin, jika perlu.
Saya sering membaca atau mendengar beberapa orang yang memperdebatkan variabel 'global' sangat buruk. Saya mengikuti alasan mereka, dan sebagian besar argumen mereka tampaknya terkait dengan extern
variabel global dalam istilah C. Apa yang mereka katakan tentu benar. Saya kadang-kadang menggunakan 1 atau 2 extern
variabel yang dideklarasikan di seluruh program ketika akan menyederhanakan banyak hal dan ketika mudah untuk melacaknya, tetapi melangkah lebih jauh akan dengan mudah membuat program tidak dapat diprediksi.
Bagaimana dengan static
variabel? Apakah mereka masih memiliki masalah yang sama dengan variabel global 'nyata'? Mungkin saya bahkan tidak perlu mengajukan pertanyaan ini dan melanjutkan jika saya pikir apa yang saya lakukan adalah benar, tetapi hari ini saya melihat jenis posting 'variabel global yang BURUK' lainnya, dan akhirnya datang ke sini berpikir mungkin ini adalah hak tempat untuk pertanyaan semacam itu. Apa yang kamu pikirkan?
Pertanyaan ini bukan merupakan duplikat dari ini karena pertanyaan ini menanyakan tentang extern
dan static
variabel non-lokal sedangkan pertanyaan lainnya adalah tentang variabel file-lingkup dan blok-lingkup static
.
Jawaban:
Dalam program C yang dirancang dengan baik, variabel file-statis mirip dengan anggota statis pribadi kelas:
Itu hanya dapat diakses oleh fungsi-fungsi dalam file itu, mirip dengan bagaimana variabel anggota statis pribadi hanya dapat diakses oleh fungsi-fungsi di kelas di mana ia didefinisikan.
Hanya ada satu salinan variabel.
Masa hidupnya adalah masa hidup program.
Suatu
extern
variabel akan menjadi variabel global sejati seperti dalam bahasa apa pun yang mendukungnya.Sebuah
static
variabel non-global tidak seburuk global; sebenarnya, mereka diperlukan dalam beberapa kasus.Akses dikendalikan melalui fungsi yang Anda tulis. Ini membantu dengan integritas data termasuk pemeriksaan batas serta keamanan utas. (catatan: ini tidak menjamin keamanan utas, ini hanyalah satu alat untuk membantu di sepanjang jalan)
Data dienkapsulasi: hanya file yang dapat mengaksesnya. Ini sedekat C dapat enkapsulasi di mana beberapa fungsi dapat mengakses variabel statis.
Variabel global buruk apa pun yang terjadi. Variabel file statis memiliki manfaat dari variabel statis pribadi tetapi tidak ada kelemahan dari variabel global.
Satu-satunya masalah tidak seperti dengan variabel statis pribadi yang benar seperti dalam C ++, file lain dapat mendeklarasikan
extern
variabel yang cocok dengan deklarasi dan Anda tidak dapat mencegah akses. Dengan kata lain, Anda mengandalkan sistem kehormatan untuk menghindari mengubahnya menjadi variabel global.sumber
Status global, termasuk
extern
variabel dan non-const
static
variabel dalam cakupan file atau fungsi seringkali dapat menjadi solusi mudah untuk masalah yang diberikan, tetapi ada tiga masalah:static
membuat kode tidak dapat diuji , karenastatic
variabel cenderung dependensi yang tidak dapat diganti. Atau dengan kata lain OOP-y: Anda tidak mengikuti Prinsip Ketergantungan Pembalikan. Saya datang ke C dan C ++ dari bahasa dinamis seperti Perl, jadi model biaya saya condong ke arah pengiriman virtual dan fungsi pointer dan sebagainya. Dengan bahasa saat ini, ada beberapa konflik antara testabilitas dan arsitektur yang baik, tapi saya pikir gangguan kecil membuat dependensi Anda eksplisit dan membiarkannya ditimpa dalam tes secara nyata diimbangi oleh kemudahan tes menulis, dan dengan demikian memastikan perangkat lunak Anda berfungsi sebagai diharapkan. Tanpa membuat kode Anda lebih dinamis, satu-satunya mekanisme yang tersedia untuk menyuntikkan dependensi untuk pengujian adalah kompilasi bersyarat.Status global mempersulit alasan tentang kebenaran , dan itu mengarah pada bug. Semakin banyak bit dan potongan memiliki akses ke variabel dan dapat memodifikasinya, semakin mudah kehilangan jejak apa yang terjadi. Sebaliknya: lebih suka penugasan variabel tunggal! Lebih suka
const
dimanapun yang masuk akal! Lebih suka menjaga variabel melalui getter dan setter di mana Anda dapat memperkenalkan pemeriksaan kebenaran. Selama negara itustatic
dan tidakextern
, itu masih mungkinuntuk mempertahankan kebenaran, tetapi selalu lebih baik untuk menganggap saya-dalam-seminggu tidak akan secerdas saya-sekarang. Terutama di C ++, kita dapat menggunakan kelas untuk memodelkan berbagai abstraksi yang membuatnya tidak mungkin untuk menyalahgunakan sesuatu, jadi cobalah untuk menggunakan sistem tipe daripada kecerdasan Anda - Anda memiliki hal-hal yang lebih penting untuk dipikirkan.Negara global mungkin menyiratkan bahwa fungsi Anda tidak masuk kembali , atau bahwa mereka hanya dapat digunakan dalam satu konteks pada suatu waktu. Bayangkan driver basis data yang hanya bisa mengelola satu koneksi! Itu batasan yang sama sekali tidak perlu. Pada kenyataannya, keterbatasan seringkali lebih halus, seperti variabel global yang digunakan untuk mengagregasi hasil. Alih-alih, buat aliran data Anda eksplisit dan lewati semuanya melalui parameter fungsi. Sekali lagi, kelas C ++ dapat membuat ini lebih mudah dikelola.
Jelas,
static const NAMED_CONSTANTS
tidak apa-apa. Menggunakanstatic
fungsi-fungsi di dalam adalah jauh lebih rumit: walaupun berguna untuk konstanta yang diinisialisasi dengan malas, ini mungkin cukup tidak dapat diuji coba. Kompromi adalah memisahkan menghitung nilai awal dari variabel statis, sehingga kedua bagian dapat diuji secara terpisah.Dalam program kecil dan mandiri, semua ini tidak masalah, dan Anda dapat terus menggunakan
static
keadaan untuk menyenangkan hati Anda. Tetapi ketika Anda melewati sekitar 500 LOC atau jika Anda menulis perpustakaan yang dapat digunakan kembali, Anda harus benar-benar mulai berpikir tentang arsitektur yang baik dan antarmuka yang baik tanpa batasan yang tidak perlu.sumber
thread_local
dan kompiler telah lama mendukungnya sebagai ekstensi sebelum standardisasi.static
variabel.Saya tidak menganggap variabel dengan cakupan file seburuk variabel global. Bagaimanapun, semua akses ke variabel-variabel ini terbatas pada satu file sumber tunggal. Dengan pembatasan itu, variabel lingkup file hampir sama baiknya atau buruk dengan anggota data statis C ++ pribadi, dan Anda tidak melarang penggunaannya, bukan?
sumber
static
penyimpanan, yang ada tepat sekali, bukan untuk setiap objek. Variabel ini tidak memerlukan turunan kelas apa pun untuk direferensikan oleh kode kelas, sehingga tidak perlu melewati referensi / pointer ke singleton. Inilah yang dicapai variabel lingkup file juga. Satu-satunya perbedaan adalah, bahwastatic
anggota memiliki ruang lingkup kelas sedangkanstatic
variabel "global" memiliki ruang lingkup file. Namun kedua cakupan ini sangat mirip, yang merupakan poin saya. Saya setuju bahwa arti yang berbedastatic
membingungkan.Itu semua terkait dengan ruang lingkup variabel (tidak konstan, sesuatu yang bisa berubah) dalam pandangan saya. Ini adalah pandangan yang diakui kurang bernuansa, tetapi ini adalah kontra pragmatis dan seruan untuk kembali ke dasar-dasar paling mendasar bagi mereka yang berkata, "Ini benar-benar jahat!" hanya untuk kemudian tersandung pada masalah yang mirip dengan yang terkait dengan apa yang mereka kritik, seperti kondisi ras.
Bayangkan Anda memiliki fungsi 50.000 baris dengan segala macam variabel yang dideklarasikan di atas dan
goto
pernyataan untuk berkeliling di semua tempat. Itu tidak terlalu menyenangkan dengan ruang lingkup variabel yang mengerikan, dan mencoba menjelaskan fungsi, dan apa yang terjadi dengan variabel-variabel tersebut, akan menjadi sangat sulit. Dalam kasus mengerikan seperti itu, perbedaan normal antara efek samping "eksternal" dan "internal" kehilangan banyak tujuan praktisnya.Bayangkan Anda memiliki program sederhana 80-baris yang baru saja Anda tulis satu kali dan engkol dengan variabel global (baik dengan tautan internal dan ruang lingkup file atau tautan eksternal, tetapi bagaimanapun programnya masih kecil). Itu tidak terlalu buruk.
Bayangkan Anda memiliki kelas mengerikan dalam bahasa berorientasi objek yang berisi logika seluruh program Anda dengan ribuan dan ribuan baris kode untuk implementasinya. Dalam hal ini variabel anggotanya lebih bermasalah daripada global dalam program 80-garis di atas.
Jika Anda ingin dapat alasan yang lebih baik dan lebih percaya diri tentang kode Anda, keamanan utasnya (atau ketiadaan), membuatnya lebih dapat diprediksi, pastikan pengujian Anda memiliki cakupan yang baik tanpa semua jenis kasus tepi potensial terlewatkan, dll. , lalu membantu mempersempit akses ke variabel.
Statika ruang lingkup file akan cenderung memiliki ruang lingkup yang lebih sempit daripada yang memiliki hubungan eksternal, tetapi sekali lagi jika file sumber Anda 100.000 baris kode, itu masih sangat lebar. Jadi untuk statika ruang lingkup file, jika Anda tidak dapat menghindarinya, saya akan mencoba untuk menjaga ruang lingkup mereka sempit dengan tidak membuat file sumber Anda yang dapat mengaksesnya ginormous, karena dalam hal itu mengurangi ruang lingkupnya adalah tentang mengurangi ukuran dan cakupan desain file sumber, yang bertentangan dengan fungsi (untuk variabel lokal, termasuk parameter), kelas (untuk variabel anggota), atau mungkin modul (untuk global dengan tautan eksternal tetapi hanya dapat diakses dalam modul), atau bahkan seluruh perangkat lunak (untuk global dengan hubungan eksternal dapat diakses oleh seluruh perangkat lunak).
sumber