Apakah setiap objek dalam C ++ bisa berubah jika tidak dinyatakan sebaliknya?
Dalam Python dan Javascript saya tidak bisa mengubah string, tuple, unicodes. Saya bertanya-tanya apakah ada sesuatu di C ++ yang tidak berubah atau setiap objek bisa berubah dan saya harus menggunakan const
jenis kualifikasi untuk membuatnya tidak berubah.
Jawaban:
Kekekalan telah dipahami dengan baik untuk beberapa waktu. Python, Java, dan C ++ memiliki model memori berbeda yang membuat perbandingan langsung menjadi sulit. Penulis artikel yang Anda kutip tampaknya tidak tahu C ++.
Seperti dalam Python, Java, dan sebagian besar bahasa multi-paradigma, C dan C ++ memungkinkan mutabilitas secara default. Inilah yang biasanya diinginkan oleh programmer: jika saya memiliki
String x
variabel, saya ingin dapat memberikan nilai barux = "foo"
.Const-system di C dan C ++ memungkinkan banyak ketidakberdayaan bernuansa yang kurang dalam Python, Java, dan bahkan Scala. Jika fungsi C ++ mengambil a
const std::string&
atau aconst char*
, ia menjanjikan (dan kompiler memastikan, sampai tingkat tertentu), bahwa fungsi ini tidak akan (tidak bisa!) Mengubah isi string itu. Diberikan objek const, kita hanya bisa memanggil metode objek yang juga ditandai sebagai const. Jika kelas C ++ hanya memiliki anggota publik yangconst
, maka objek secara efektif tidak dapat diubah.Namun, ini kadang membingungkan karena dalam objek C dan C ++ lokasi memori, dan variabel adalah nama untuk lokasi memori. Sebaliknya, variabel dalam Python dan Java adalah nama untuk pointer ke objek. Dalam bahasa dengan semantik referensi,
x = y
berarti "buat x arahkan ke objek yang sama dengan y". Karena kita hanya menyalin pointer, ini dimungkinkan dengan objek yang tidak berubah. Dalam bahasa dengan semantik nilai seperti C ++, itu berarti "perbarui kontenx
dengan konteny
". Oleh karena itu, jika penugasan kembali suatu variabel diinginkan dalam C atau C ++, variabel tersebut mungkin tidak memiliki tipe const. Untuk melakukan ini dengan objek yang tidak dapat diubah, kita harus menggunakan pointer secara eksplisit.Bahwa Java dan Python menggunakan objek string yang tidak dapat diubah adalah keputusan desain dasar, tetapi tidak secara langsung terhubung ke manfaat ketetapan dalam lingkungan multithreading. Salah satu alasannya adalah bahwa string literal dalam kode sumber dapat dikumpulkan yang mengurangi jumlah objek. Ini dimungkinkan dalam C / C ++ juga. Dalam C ++ literal
"foo"
memiliki tipeconst char[4]
(karakter ke-4 adalah terminating'\0'
). Alasan lain adalah bahwa entri dalam set dan kunci dalam dicts / peta tidak boleh diubah. Karena string digunakan secara luas sebagai kunci dict (sebagian besar objek Python adalah dict), immutability menghapus sumber kesalahan yang umum. Di Jawa, alasan lain untuk string yang tidak dapat diubah adalah model keamanan Java. Semua alasan ini sama sekali tidak terkait dengan multithreading.Jika Jawa dibangun dengan pertimbangan kekekalan, bahasa akan terlihat sangat berbeda. Meskipun sangat terinspirasi oleh C ++, para desainer berusaha keras untuk membuat bahasa yang lebih sederhana, menghilangkan const adalah salah satu langkahnya. Hal Java yang setara dengan referensi const C ++ adalah adaptor atau dekorator yang mengimplementasikan metode mutasi apa pun
throws new NotImplementedException()
, dan meneruskan metode non-mutasi panggilan ke koleksi aktual. Fakta bahwa antarmuka java.util interface semua menyiratkan mutabilitas adalah tanda yang jelas bahwa mereka tidak berusaha untuk bahasa pertama-immutability.Solusi yang diajukan Java untuk memecahkan masalah konkurensi bukanlah kekekalan, tetapi penguncian yang luas. Setiap objek tunggal berisi mutex yang dapat digunakan untuk
synchronized
blok atau seluruh metode. Ternyata, itu tidak baik untuk kinerja, tidak skala dengan sangat baik, dan cukup rawan kesalahan - Anda masih harus berurusan dengan negara global yang bisa berubah.sumber
mut
kata kunci, dan di mana mutabilitas yang tidak perlu ditandai oleh kompiler) cenderung mendukung hipotesis saya: di Rust, Anda memiliki lebih banyaklet
binding daripada yang Anda milikilet mut
.for x in 1..10
tidak digunakanlet mut
untuk mendefinisikan variabel loop, tapi jelas itu membutuhkan beberapa mutabilitas (hanya pada level loop, tidak di dalam tubuh loop).const T o = [&]{T o; o.init(...); return o;}();
... yay untuk API yang tidak dirancang dengan pertimbangan keabadian.Hampir. Bahasa itu sendiri memperlakukan segala sesuatu sebagai bisa berubah kecuali Anda menggunakan
const
, tetapi masih mungkin untuk membangun objek tidak berubah tanpa memberitahu kompiler mereka tidak dapat diubah, dengan hanya tidak menyediakan cara untuk bermutasi.Sebagai contoh, ambil kelas ini:
Contoh dari
MyClass
tidak dapat diubah, karena tidak ada cara untuk memutasi mereka - tetapi tidak ada dalam kode yang benar-benar menyatakan mereka tidak dapat diubah. (Ini adalah cara yang sama bahwa instanceString
kelas Java tidak berubah)sumber
delete
operator penugasan salinan di sini juga memastikan tidak dapat menetapkan dari referensi nilai melalui operasi pemindahan-tugas?value
const, dan untuk mendeklarasikangetValue()
fungsi const.Tidak, ada satu pengecualian: Lambdas dan ekstensi objek yang mereka tangkap tidak dapat diubah secara default:
Jadi, alih-alih menambahkan
const
untuk membuatnya tidak berubah, Anda menambahkanmutable
untuk membuatnya tidakconst
.sumber