Untuk memulai, Anda mungkin tahu bahwa const
dapat digunakan untuk membuat data objek atau pointer tidak dapat dimodifikasi atau keduanya.
const Object* obj; // can't change data
Object* const obj; // can't change pointer
const Object* const obj; // can't change data or pointer
Namun Anda juga dapat menggunakan sintaks:
Object const *obj; // same as const Object* obj;
Satu-satunya hal yang tampaknya penting adalah sisi asterisk mana yang Anda masukkan const
kata kunci. Secara pribadi saya lebih suka memakai const
di sebelah kiri jenis untuk menentukan data itu tidak dapat dimodifikasi karena saya menemukan itu membaca lebih baik dalam pola pikir kiri-ke-kanan saya tetapi sintaks mana yang lebih dulu?
Lebih penting lagi mengapa ada dua cara yang benar untuk menentukan const
data dan dalam situasi apa Anda lebih suka atau membutuhkan satu dari yang lain jika ada?
Edit:
Jadi sepertinya ini adalah keputusan yang sewenang-wenang ketika standar untuk bagaimana kompiler harus menafsirkan hal-hal yang dirancang jauh sebelum saya lahir. Karena const
diterapkan pada apa yang ada di sebelah kiri kata kunci (secara default?) Saya kira mereka pikir tidak ada salahnya menambahkan "pintasan" untuk menerapkan kata kunci dan mengetikkan kualifikasi dengan cara lain setidaknya sampai saat deklarasi berubah oleh parsing * atau & ...
Ini adalah kasus di C juga maka saya berasumsi?
const
setelah jenis, misalnya#define MAKE_CONST(T) T const
bukannya#define MAKE_CONST(T) const T
sehinggaMAKE_CONST(int *)
akan benar berkembang menjadiint * const
bukanconst int *
.Jawaban:
Pada dasarnya, alasan bahwa posisi
const
dalam specifier sebelum tanda bintang tidak menjadi masalah adalah bahwa tata bahasa C didefinisikan seperti itu oleh Kernighan dan Ritchie.Alasan mereka mendefinisikan tata bahasa dengan cara ini adalah kemungkinan bahwa kompiler C mereka mem-parsing input dari kiri ke kanan dan selesai memproses masing-masing token saat dikonsumsi. Mengkonsumsi
*
token mengubah status deklarasi saat ini menjadi tipe pointer. Mengalamiconst
setelah*
berarticonst
kualifikasi diterapkan ke deklarasi pointer; menjumpainya sebelum*
sarana kualifikasi diterapkan pada data yang ditunjukkan.Karena makna semantik tidak berubah jika
const
kualifikasi muncul sebelum atau setelah penspesifikasi tipe, itu diterima baik cara.Jenis kasus serupa muncul ketika mendeklarasikan pointer fungsi, di mana:
void * function1(void)
mendeklarasikan fungsi yang mengembalikanvoid *
,void (* function2)(void)
mendeklarasikan pointer fungsi ke fungsi yang mengembalikanvoid
.Sekali lagi hal yang perlu diperhatikan adalah bahwa sintaks bahasa mendukung parser kiri-ke-kanan.
sumber
*
kompiler parser tidak tahu itu adalah pointer maka itu adalah const untuk nilai data. Setelah * itu terkait dengan pointer konstan. Cemerlang. Dan akhirnya itu menjelaskan mengapa saya bisa melakukannyaconst char
jugachar const
.const
untuk selalu datang setelah hal itu memenuhi syarat ... tepat sehingga saya selalu bisa selesai memproses const segera setelah saya mengkonsumsinya. Jadi ini tampaknya menjadi argumen untuk melarang western-const, daripada membiarkannya.++
operator? "Kalimatnya", imho, membantuku menyadari bahwa tidak ada alasan khusus selain karena mereka bisa. Mungkin mereka akan membuat pilihan yang berbeda hari ini / mungkin tidak.Aturannya adalah:
Saya lebih suka menggunakan const di sebelah kanan hal menjadi const hanya karena itu adalah konst "asli" cara didefinisikan.
Tapi saya pikir ini adalah sudut pandang yang sangat subyektif.
sumber
Object const *
adalah pointer ke Object const. Jika Anda meletakkanconst
di sebelah kiri, itu akan dibaca sebagai pointer ke Obyek yang const, yang tidak benar-benar mengalir dengan baik.const
bukan kelas penyimpanan, tetapi orang bukan pengurai).Saya lebih suka sintaks kedua. Ini membantu saya melacak 'apa' yang konstan dengan membaca deklarasi tipe dari kanan ke kiri:
sumber
Object const* const
tidakconst const Object*
. "const" tidak boleh berada di sebelah kiri kecuali dalam kasus khusus di mana begitu banyak orang benar-benar menyukainya. (Lihat Heath di atas.)Urutan kata kunci dalam deklarasi tidak semuanya diperbaiki. Ada banyak alternatif untuk "tatanan yang benar". Seperti ini
atau seharusnya begitu
??
sumber
decl-specifier-seq
adalah urutandecl-specifier
s. Tidak ada urutan yang diberikan oleh tata bahasa, dan jumlah kejadian untuk setiap kata kunci hanya dibatasi oleh beberapa aturan semantik (Anda dapat memiliki satuconst
tetapi dualong
:-)unsigned
adalah tipe, sama denganunsigned int
danint unsigned
.unsigned long
adalah tipe lain, sama denganunsigned long int
danint long unsigned
. Lihat polanya?;)
. OK, terima kasihstatic
kata-kata yang campur aduk, tetapi baru-baru ini ada kompiler yang mengeluh bahwastatic
harus didahulukan.Aturan pertama adalah menggunakan format apa pun yang dibutuhkan oleh standar pengkodean lokal Anda. Setelah itu: meletakkan
const
di depan tidak akan berakhir kebingungan ketika typedefs terlibat, misalnya:Jika standar pengodean Anda memungkinkan typedef tentang pointer, maka itu benar-benar harus bersikeras menempatkan const setelah tipe. Dalam setiap kasus tetapi ketika diterapkan pada tipe, const harus mengikuti apa yang berlaku untuknya, sehingga koherensi juga berpendapat mendukung const setelah. Tetapi pedoman pengkodean lokal mengalahkan semua ini; perbedaan biasanya tidak cukup penting untuk kembali dan mengubah semua kode yang ada.
sumber
const std::string::const_iterator
juga untuk ukuran yang baik;)const IntPtr p1
berarti selain "pointer integer konstan" (yaitu, "pointer konstan ke integer")? Tidak ada orang yang waras, bahkan tanpa mengetahui bagaimanaIntPtr
didefinisikan, akan berpikir bahwap1
itu bisa berubah. Dan dalam hal ini, mengapa ada yang salah menganggap itu*p1
tidak berubah? Terlebih lagi, menempatkan const di tempat lain (misalnya,IntPtr const p1
), tidak mengubah semantik sama sekali.std::vector<T>::const_iterator
, di mana itu bukan iterator yang merupakan const, tetapi apa yang ditunjuknya).Ada alasan historis bahwa kiri atau kanan dapat diterima. Stroustrup telah menambahkan const ke C ++ pada tahun 1983 , tetapi tidak membuatnya ke C sampai C89 / C90.
Di C ++ ada alasan bagus untuk selalu menggunakan const di sebelah kanan. Anda akan konsisten di mana saja karena fungsi const member harus dinyatakan dengan cara ini:
sumber
const int& getInt();
int& const getInt();
int const& getInt();
lebih baik daripada yang setaraconst int& getInt();
sedangkanint& const getInt();
Anda membandingkannya dengan berlebihan (referensi sudah const) meskipun legal dan biasanya akan memberikan peringatan. Lagi pula, const pada fungsi anggota mengubahthis
pointer di fungsi dariFoo* const
menjadiFoo const* const
.const
pada fungsi anggota tidak berarti sama sekali hal yang sama — atau apakahvoid set(int)&;
semacam referensi ke fungsi?