Saya tidak berbicara tentang pointer ke nilai const, tetapi pointer pointer sendiri.
Saya belajar C dan C ++ di luar hal-hal yang sangat mendasar dan baru hari ini saya menyadari bahwa pointer diberikan nilai ke fungsi, yang masuk akal. Ini berarti bahwa di dalam suatu fungsi saya dapat membuat titik pointer yang disalin ke beberapa nilai lain tanpa mempengaruhi pointer asli dari pemanggil.
Jadi apa gunanya memiliki header fungsi yang mengatakan:
void foo(int* const ptr);
Di dalam fungsi seperti itu Anda tidak dapat membuat titik ptr ke sesuatu yang lain karena itu adalah const dan Anda tidak ingin itu diubah, tetapi fungsi seperti ini:
void foo(int* ptr);
Apakah berhasil juga! karena pointer disalin bagaimanapun dan pointer di pemanggil tidak terpengaruh walaupun Anda memodifikasi salinan. Jadi apa kelebihan const?
const
parameter apa pun .const
jaminan -koreksi. Itu hanya membuat kita merasa lebih yakin bahwa kode kita pasti benar.Jawaban:
const
adalah alat yang harus Anda gunakan dalam mengejar konsep C ++ yang sangat penting:Meskipun itu tidak mengubah fungsionalitas, menambahkan
const
menghasilkan kesalahan kompiler ketika Anda melakukan hal-hal yang tidak ingin Anda lakukan. Bayangkan salah ketik berikut:Jika Anda menggunakan
int* const
, ini akan menghasilkan kesalahan kompiler karena Anda mengubah nilainya menjadiptr
. Menambahkan batasan melalui sintaks adalah hal yang baik secara umum. Hanya saja jangan terlalu jauh - contoh yang Anda berikan adalah kasus di mana kebanyakan orang tidak repot-repot menggunakannyaconst
.sumber
Saya membuat titik menggunakan hanya
const
argumen karena ini memungkinkan lebih banyak pemeriksaan kompiler: jika saya secara tidak sengaja menetapkan ulang nilai argumen di dalam fungsi, kompiler menggigit saya.Saya jarang menggunakan kembali variabel, lebih bersih untuk membuat variabel baru untuk menyimpan nilai-nilai baru, jadi pada dasarnya semua deklarasi variabel saya
const
(kecuali untuk beberapa kasus seperti variabel loop di manaconst
akan mencegah kode bekerja).Perhatikan bahwa ini hanya masuk akal dalam definisi suatu fungsi. Itu tidak termasuk dalam deklarasi , yang adalah apa yang dilihat pengguna. Dan pengguna tidak peduli apakah saya menggunakan
const
parameter di dalam fungsi.Contoh:
Perhatikan bagaimana argumen dan variabel lokalnya
const
. Tidak perlu tetapi dengan fungsi yang bahkan sedikit lebih besar, ini telah berulang kali menyelamatkan saya dari membuat kesalahan.sumber
+1
dariconst
fanatik -sesuai lain . Namun, saya lebih suka kompiler saya untuk menyalak. Saya membuat terlalu banyak kesalahan dan akan sangat menderita jika mereka menggigit.const
kecuali ada alasan bagus". Ada beberapa pengecualian, misalnya Salin dan tukarconst
dari argumen, dan lebih baik berikan komentar mengapa. Sedikit kerja ekstra itu tidak membenarkan menandai semua argumen sebagai tidak-const
baku dan membuka diri terhadap semua potensi kesalahan yang terjadi.Pertanyaan Anda menyentuh sesuatu yang lebih umum: Haruskah argumen fungsi menjadi konst?
Keteguhan argumen nilai (seperti pointer Anda) adalah detail implementasi , dan itu tidak membentuk bagian dari deklarasi fungsi. Ini berarti bahwa fungsi Anda selalu seperti ini:
Ini sepenuhnya tergantung pada pelaksana fungsi apakah dia ingin menggunakan variabel argumen fungsi-lingkup dalam bisa berubah atau dengan cara yang konstan:
Jadi, ikuti aturan sederhana untuk tidak pernah memasukkan
const
deklarasi (header), dan memasukkannya ke dalam definisi (implementasi) jika Anda tidak ingin atau perlu memodifikasi variabel.sumber
const
, deklarasi dan (bagian prototipe) definisi umumnya akan sama.const
dalam deklarasi. Ini sepenuhnya terserah Anda jika Anda ingin menambahkan kualifikasi dalam implementasi.const
deklarasi tetapi bukan definisi yang masuk akal. Hanya terasa seperti kesalahan dalam bahasa bahwa ini adalah satu-satunya kasus di mana membuat pernyataan dan definisi tidak identik masuk akal. (Ini bukan satu-satunya kesalahan C, tentu saja.)Kualifikasi const tingkat atas dibuang dalam deklarasi, sehingga deklarasi dalam pertanyaan menyatakan fungsi yang persis sama. Di sisi lain, dalam definisi (implementasi) kompiler akan memverifikasi bahwa jika Anda menandai pointer sebagai const, itu tidak dimodifikasi di dalam tubuh fungsi.
sumber
int* t ptr
adalah kesalahan sintaksis. Tanpa itu, keduanya identik untuk tujuan overloading.Anda benar, bagi penelepon itu tidak ada bedanya. Tetapi bagi penulis fungsi itu bisa menjadi jaring pengaman "oke, saya harus memastikan saya tidak membuat titik ini ke hal yang salah". Tidak terlalu berguna tetapi juga tidak berguna.
Ini pada dasarnya sama dengan memiliki
int const the_answer = 42
dalam program Anda.sumber
const int
danint const
setara, sementaraconst int*
danint* const
memiliki dua arti berbeda!int const
bagian; Saya telah meletakkan jenis sebelum const (itu terdengar tidak wajar) untuk beberapa waktu dan saya menyadari perbedaannya. Artikel ini mungkin terbukti bermanfaat. Saya sendiri punya sedikit alasan berbeda untuk beralih ke gaya ini.Ada banyak
const
kata kunci, ini agak rumit. Secara umum, menambahkan banyak const ke program Anda dianggap praktik pemrograman yang baik, cari web untuk "const constness" dan Anda akan menemukan banyak info tentang itu.Kata kunci const adalah yang disebut "jenis kualifikasi", yang lain adalah
volatile
danrestrict
. Setidaknya volatile mengikuti aturan (membingungkan) yang sama dengan const.Pertama-tama, kata kunci const melayani dua tujuan. Yang paling jelas adalah melindungi data (dan petunjuk) dari penyalahgunaan yang disengaja atau tidak disengaja dengan membuatnya hanya baca-saja. Setiap upaya untuk memodifikasi variabel const akan terlihat oleh kompiler pada waktu kompilasi.
Tetapi ada juga tujuan lain dalam sistem apa pun dengan memori hanya baca, yaitu untuk memastikan bahwa variabel tertentu dialokasikan di dalam memori tersebut - bisa jadi EEPROM atau flash misalnya. Ini dikenal sebagai memori non-volatile, NVM. Variabel yang dialokasikan dalam NVM tentu saja akan tetap mengikuti semua aturan variabel const.
Ada beberapa cara berbeda untuk menggunakan
const
kata kunci:Deklarasikan variabel konstan.
Ini dapat dilakukan sebagai
Kedua bentuk ini sepenuhnya setara . Gaya yang terakhir dianggap gaya yang buruk dan tidak boleh digunakan.
Alasan mengapa baris kedua dianggap gaya yang buruk, mungkin karena "penentu kelas penyimpanan" seperti statis dan eksternal juga dapat dideklarasikan setelah tipe aktual,
int static
dll. Tetapi melakukannya untuk penentu kelas penyimpanan dianggap sebagai fitur usang. oleh komite C (draft ISO 9899 N1539, 6.11.5). Oleh karena itu, demi konsistensi, orang tidak boleh menulis kualifikasi jenis dengan cara itu juga. Tidak ada tujuan lain selain membingungkan pembaca.Deklarasikan pointer ke variabel konstan.
Ini berarti bahwa isi 'X' tidak dapat dimodifikasi. Ini adalah cara normal Anda mendeklarasikan pointer seperti ini, terutama sebagai bagian dari parameter fungsi untuk "kebenaran konst". Karena 'X' sebenarnya tidak harus dideklarasikan sebagai const, itu bisa berupa variabel apa saja. Dengan kata lain Anda selalu dapat "memutakhirkan" variabel ke const. Secara teknis, C juga memungkinkan penurunan versi dari const ke variabel polos dengan typecasts eksplisit, tetapi melakukan hal itu dianggap pemrograman yang buruk dan kompiler biasanya memberikan peringatan terhadapnya.
Nyatakan pointer konstan
Ini berarti bahwa pointer itu sendiri konstan. Anda dapat mengubah apa yang ditunjukkannya, tetapi Anda tidak dapat memodifikasi pointer itu sendiri. Ini tidak memiliki banyak kegunaan, ada beberapa, seperti memastikan bahwa pointer-menunjuk-di (pointer-to-pointer) tidak memiliki alamat itu diubah saat diteruskan sebagai parameter ke suatu fungsi. Anda harus menulis sesuatu yang tidak terlalu mudah dibaca seperti ini:
Saya ragu banyak programmer C bisa mendapatkan const dan * di sana. Saya tahu saya tidak bisa - saya harus memeriksa dengan GCC. Saya pikir itu sebabnya Anda jarang pernah melihat sintaks untuk pointer-to-pointer, meskipun dianggap praktik pemrograman yang baik.
Pointer konstan juga dapat digunakan untuk memastikan bahwa variabel pointer itu sendiri dideklarasikan dalam memori read-only, misalnya Anda ingin mendeklarasikan semacam tabel pencarian berbasis pointer dan mengalokasikannya dalam NVM.
Dan tentu saja, seperti yang ditunjukkan oleh jawaban lain, pointer konstan juga dapat digunakan untuk menegakkan "kebenaran konst".
Deklarasikan pointer konstan ke data konstan
Ini adalah dua tipe pointer yang dijelaskan di atas digabungkan, dengan semua atribut keduanya.
Deklarasikan fungsi anggota hanya-baca (C ++)
Karena ini ditandai C ++, saya juga harus menyebutkan bahwa Anda dapat mendeklarasikan fungsi anggota kelas sebagai const. Ini berarti bahwa fungsi tidak diperbolehkan untuk memodifikasi anggota kelas yang lain ketika dipanggil, yang keduanya mencegah programmer dari kesalahan yang tidak disengaja tetapi juga memberitahu pemanggil fungsi anggota bahwa mereka tidak akan mengacaukan apa pun. dengan menyebutnya. Sintaksnya adalah:
sumber
(IMO) itu benar-benar tidak masuk akal sebagai default. default yang lebih masuk akal adalah untuk lulus sebagai pointer yang tidak dapat dipindahkan (
int* const arg
). yaitu, saya lebih suka bahwa pointer lewat karena argumen secara implisit dinyatakan sebagai konst.keuntungannya adalah itu cukup mudah dan kadang-kadang tidak jelas ketika Anda memodifikasi alamat yang ditunjuk argumen, sehingga Anda dapat memperkenalkan bug ketika tidak mudah dikenali. mengubah alamat tidak lazim. akan lebih jelas untuk membuat variabel lokal jika maksud Anda adalah memodifikasi alamat. juga, manipulasi pointer mentah adalah cara mudah untuk memperkenalkan bug.
jadi lebih jelas untuk melewati alamat yang tidak dapat diubah dan membuat salinan (dalam kasus-kasus yang tidak biasa) ketika Anda ingin mengubah alamat yang ditunjuk oleh argumen:
menambahkan bahwa lokal sebenarnya gratis, dan mengurangi kemungkinan kesalahan, sambil meningkatkan keterbacaan.
di tingkat yang lebih tinggi: jika Anda memanipulasi argumen sebagai array, biasanya lebih jelas dan lebih sedikit kesalahan cenderung untuk klien menyatakan argumen sebagai wadah / koleksi.
secara umum, menambahkan const ke nilai, argumen, dan alamat adalah ide yang bagus karena Anda tidak selalu menyadari efek samping, yang dengan senang hati dikompilasi oleh kompiler. oleh karena itu, ini berguna seperti const seperti yang digunakan dalam beberapa kasus lain (misalnya pertanyaannya mirip dengan 'Mengapa saya harus mendeklarasikan nilai const?'). untungnya, kami juga memiliki referensi, yang tidak dapat dipindahkan.
sumber
const
kata kunci, itu harus memilikimutable
kata kunci (well, ia memiliki, tetapi dengan semantik yang salah).Jika Anda melakukan embedded system atau pemrograman driver perangkat di mana Anda memiliki perangkat yang dipetakan memori maka kedua bentuk 'const' sering digunakan, satu untuk mencegah penunjuk dari dipindahkan (karena menunjuk ke alamat perangkat keras tetap.) Dan, jika perangkat register it menunjuk ke register hardware read-only maka const lain akan mendeteksi banyak kesalahan pada waktu kompilasi daripada runtime.
Sebuah register chip periferal 16 bit read-only mungkin terlihat seperti:
static const unsigned short *const peripheral = (unsigned short *)0xfe0000UL;
Kemudian Anda dapat dengan mudah membaca register perangkat keras tanpa harus menggunakan bahasa assembly:
input_word = *peripheral;
sumber
int iVal = 10; int * const ipPtr = & iVal;
Sama seperti variabel const normal, pointer const harus diinisialisasi ke nilai pada saat deklarasi, dan nilainya tidak dapat diubah.
Ini berarti pointer const akan selalu menunjuk ke nilai yang sama. Dalam kasus di atas, ipPtr akan selalu menunjuk ke alamat iVal. Namun, karena nilai yang ditunjuk masih non-const, adalah mungkin untuk mengubah nilai yang ditunjuk melalui dereferencing pointer:
* ipPtr = 6; // diizinkan, karena pnPtr menunjuk ke non-const int
sumber
Pertanyaan yang sama dapat ditanyakan tentang jenis lain (bukan hanya petunjuk):
sumber
Pertanyaan Anda benar-benar lebih lanjut tentang mengapa mendefinisikan variabel apa pun sebagai const bukan hanya parameter pointer pointer ke suatu fungsi. Aturan yang sama berlaku di sini seperti ketika Anda mendefinisikan variabel apa pun sebagai konstan, jika parameternya berfungsi atau variabel anggota atau variabel lokal.
Dalam kasus khusus Anda, secara fungsional itu tidak membuat perbedaan seperti dalam banyak kasus lain ketika Anda mendeklarasikan variabel lokal sebagai const tetapi itu membuat batasan bahwa Anda tidak dapat memodifikasi variabel ini.
sumber
Melewati sebuah pointer const ke suatu fungsi tidak masuk akal, karena akan diteruskan oleh nilai. Itu hanya salah satu dari hal-hal yang diizinkan oleh desain bahasa umum. Melarangnya hanya karena itu tidak masuk akal hanya akan membuat spec bahasa. lebih besar.
Jika Anda berada di dalam suatu fungsi tentu saja merupakan kasus lain. Memiliki pointer yang tidak dapat mengubah apa yang ditunjukkannya adalah pernyataan yang membuat kode lebih jelas.
sumber
Saya kira keuntungannya adalah bahwa kompiler dapat melakukan optimasi yang lebih agresif di dalam fungsi mengetahui bahwa pointer ini tidak dapat berubah.
Ini juga menghindari mis. meneruskan pointer ini ke subfungsi yang menerima referensi pointer non-const (dan karena itu bisa mengubah pointer seperti
void f(int *&p)
), tapi saya setuju, bahwa kegunaannya agak terbatas dalam kasus ini.sumber
Contoh di mana pointer const sangat dapat diterapkan dapat ditunjukkan demikian. Pertimbangkan Anda memiliki kelas dengan array dinamis di dalamnya, dan Anda ingin memberikan akses pengguna ke array tetapi tanpa memberi mereka hak untuk mengubah pointer. Mempertimbangkan:
Yang menghasilkan:
Tetapi jika kita coba ini:
Kita mendapatkan:
Jadi jelas kita bisa memodifikasi isi array, tetapi bukan pointer array. Baik jika Anda ingin memastikan pointer memiliki status yang konsisten ketika meneruskannya kembali ke pengguna. Namun ada satu tangkapan:
Kami masih dapat menghapus referensi memori pointer, meskipun kami tidak dapat memodifikasi pointer itu sendiri.
Jadi jika Anda ingin referensi memori selalu menunjuk ke sesuatu (IE tidak pernah dimodifikasi, mirip dengan cara kerja referensi saat ini), maka itu sangat berlaku. Jika Anda ingin pengguna memiliki akses penuh dan memodifikasinya, maka non-const adalah untuk Anda.
Edit:
Setelah mencatat komentar okorz001 karena tidak dapat menetapkan karena GetArray () menjadi operan bernilai tepat, komentarnya sepenuhnya benar, tetapi hal di atas masih berlaku jika Anda mengembalikan referensi ke pointer (saya kira saya berasumsi GetArray adalah merujuk referensi), misalnya:
Akan kembali yang pertama menghasilkan kesalahan:
Tetapi yang kedua akan terjadi dengan riang meskipun ada konsekuensi potensial di bawahnya.
Jelas, pertanyaan akan diajukan 'mengapa Anda ingin mengembalikan referensi ke pointer'? Ada contoh langka di mana Anda perlu menetapkan memori (atau data) langsung ke pointer asli yang bersangkutan (misalnya, membangun malloc Anda sendiri / front-end gratis / baru atau gratis), tetapi dalam kasus tersebut itu adalah referensi non-const . Referensi ke pointer const Saya belum pernah menemukan situasi yang akan menjamin itu (kecuali mungkin sebagai variabel referensi const dinyatakan daripada jenis kembali?).
Pertimbangkan jika kita memiliki fungsi yang mengambil pointer const (versus yang tidak):
Kesalahan dalam const menghasilkan pesan:
Mana yang baik karena kita mungkin tidak ingin melakukan itu, kecuali kita ingin menyebabkan masalah yang disebutkan dalam komentar. Jika kami mengedit penurunan dalam fungsi const, berikut ini terjadi:
Jelas, meskipun A adalah 'Data [1]', itu diperlakukan sebagai 'Data [0]' karena pointer NonConst mengizinkan operasi penurunan. Dengan const diterapkan, seperti orang lain menulis, kami menangkap bug potensial sebelum terjadi.
Salah satu pertimbangan utama lainnya, adalah bahwa pointer const dapat digunakan sebagai referensi semu, dalam hal referensi menunjuk ke tidak dapat diubah (orang bertanya-tanya, jika mungkin ini adalah bagaimana itu diterapkan). Mempertimbangkan:
Ketika mencoba mengkompilasi, menghasilkan kesalahan berikut:
Yang mungkin merupakan hal yang buruk jika referensi konstan ke A diinginkan. Jika
B = NULL
dikomentari, kompiler akan dengan senang hati membiarkan kami memodifikasi*B
dan karena itu A. Ini mungkin tidak berguna dengan int, tetapi pertimbangkan jika Anda memiliki satu posisi aplikasi grafis di mana Anda ingin pointer yang tidak dapat dimodifikasi yang merujuk padanya yang dapat Anda lewati sekitar.Penggunaannya adalah variabel (alasan permainan yang tidak diinginkan), tetapi digunakan dengan benar, itu adalah alat lain dalam kotak untuk membantu pemrograman.
sumber
Temp.GetArray() = NULL
gagal karenaTemp.GetArray()
merupakan nilai, bukan karena memenuhi syarat. Selain itu, saya percaya const-kualifikasi dilepaskan dari semua tipe pengembalian.Tidak ada yang istimewa tentang pointer di mana Anda tidak akan pernah ingin mereka menjadi const. Sama seperti Anda dapat memiliki
int
nilai konstanta anggota kelas , Anda juga dapat memiliki pointer konstan untuk alasan yang sama: Anda ingin memastikan bahwa tidak ada yang pernah mengubah apa yang ditunjukkan. Referensi C ++ agak membahas hal ini, tetapi perilaku pointer diwarisi dari C.sumber
Saya percaya ini akan mencegah kode dari menambah atau mengurangi pointer di dalam fungsi body.
sumber
Jenis mendeklarasikan variabel seperti-
(1) Mendeklarasikan variabel konstan.
DataType const varibleName;
const dataType* PointerVaribleName=&X;
dataType* const PointerVaribleName=&X;
sumber