Jual saya di const benar

133

Jadi mengapa tepatnya selalu disarankan untuk menggunakan const sesering mungkin? Sepertinya saya bahwa menggunakan const bisa lebih menyakitkan daripada bantuan dalam C ++. Tapi sekali lagi, saya datang pada ini dari perspektif python: jika Anda tidak ingin sesuatu diubah, jangan mengubahnya. Maka dengan itu, ada beberapa pertanyaan:

  1. Sepertinya setiap kali saya menandai sesuatu sebagai const, saya mendapatkan kesalahan dan harus mengubah beberapa fungsi lain menjadi const juga. Maka ini menyebabkan saya harus mengubah lain fungsi di tempat lain. Apakah ini sesuatu yang semakin mudah dengan pengalaman?

  2. Apakah manfaat menggunakan const benar-benar cukup untuk mengimbangi masalah? Jika Anda tidak berniat mengubah objek, mengapa tidak hanya menulis kode yang tidak mengubahnya?

Saya harus mencatat bahwa pada titik waktu ini, saya paling fokus pada manfaat menggunakan const untuk tujuan perbaikan dan pemeliharaan, meskipun itu juga baik untuk memiliki gagasan tentang implikasi kinerja.

Jason Baker
sumber
1
8 tahun retrospektif lama, tapi .. Bagaimana kalau mempercepat kode Anda 100x (lihat ini langsung)?
lorro
1
Periksa jawaban saya di sini (pertanyaan terkait, saya akan mengatakan jawaban yang sama): stackoverflow.com/questions/42310477/... BTW: I love loveconst
Gines Hidalgo

Jawaban:

158

Ini adalah artikel definitif tentang "const correctness": https://isocpp.org/wiki/faq/const-correctness .

Singkatnya, menggunakan const adalah praktik yang baik karena ...

  1. Ini melindungi Anda dari secara tak sengaja mengubah variabel yang tidak dimaksudkan untuk diubah,
  2. Ini melindungi Anda dari membuat tugas variabel yang tidak disengaja, dan
  3. Kompilator dapat mengoptimalkannya. Misalnya, Anda dilindungi dari

    if( x = y ) // whoops, meant if( x == y )

Pada saat yang sama, kompiler dapat menghasilkan kode yang lebih efisien karena ia tahu persis bagaimana keadaan variabel / fungsi setiap saat. Jika Anda menulis kode C ++ yang ketat, ini bagus.

Anda benar karena sulit untuk menggunakan const-correctness secara konsisten, tetapi kode akhir lebih ringkas dan lebih aman untuk diprogram. Ketika Anda melakukan banyak pengembangan C ++, manfaat ini cepat terwujud.

Jordan Parmer
sumber
Saya selalu berasumsi bahwa nilai const bisa di-cache secara bebas dan dengan demikian menghindari banyak masalah konkurensi atau meningkatkan kecepatan. Benarkah itu?
Phil H
3
Tentu. constvariabel dapat meningkatkan kecepatan dalam arti bahwa kompiler dapat menghasilkan kode yang lebih optimal karena ia tahu maksud penuh dan penggunaan variabel. Apakah Anda akan melihat perbedaannya? Nah, itu masih bisa diperdebatkan pada aplikasi Anda. Sejauh menyangkut concurrency, const-variable adalah read-only yang berarti tidak ada kebutuhan untuk kunci eksklusif pada variabel-variabel tersebut karena nilainya akan selalu sama.
Jordan Parmer
4
Pada C ++ 11 perpustakaan standar juga mengasumsikan constberarti thread-safe dan memperlakukan kode Anda sendiri dengan cara ini membuatnya lebih mudah untuk memeriksa kemungkinan masalah multi-threading dan merupakan cara mudah untuk memberikan jaminan API untuk pengguna API Anda.
sore
3
Bagi saya, salah satu nilai tambah terbesar dari kebenaran const adalah bahwa Anda tahu hanya dengan melihat prototipe fungsi ketika pointer merujuk data yang tidak pernah dimutasi oleh fungsi (yaitu input saja).
cp.engr
1
Jangan lupa bahwa ada ketegasan logis dan fisik . Setiap objek agregat yang terkandung yang ditandai sebagai bisa berubah dapat berubah, meskipun menandainya dengan demikian menyiratkan bahwa itu tidak ada hubungannya dengan ketegasan logis dari objek yang mengandung.
Adrian
128

Berikut adalah sepotong kode dengan kesalahan umum yang benar dapat melindungi Anda dari:

void foo(const int DEFCON)
{
   if (DEFCON = 1)     //< FLAGGED AS COMPILER ERROR! WORLD SAVED!
   {
       fire_missiles();
   }
}
Doug T.
sumber
19
Jadi kami mengatakan bahwa const diperlukan karena beberapa orang bodoh memilih "=" sebagai operator penugasan di C? ;-)
Steve Jessop
37
Tentu saja, kebanyakan kompiler modern memperingatkan tentang penugasan dalam kondisi dan kita semua mengaktifkan peringatan memperlakukan sebagai flag kesalahan, kanan: ->
Jack Bolding
7
Jangan terlalu keras pada contoh itu: Ini adalah contoh yang sama diinjili oleh beberapa pengembang untuk meyakinkan kita untuk menggunakan if (0 == i) alih-alih if (i == 0). Akhirnya, pola kode Doug dapat digunakan di luar pernyataan "jika". Yang penting itu menunjukkan salah satu manfaat dari const dengan cara yang lucu. + 1.
paercebal
2
Beberapa kompiler (dan serat) telah memperingatkan tentang ini untuk waktu yang lama, dan itu jauh lebih berguna untuk menangkap kesalahan ketik ini daripada const: codepad.org/Nnf5JUXV .
7
@Roger Anda berasumsi bahwa kita hidup di dunia di mana bangunan bersih dan bebas peringatan. Pengalaman saya adalah bahwa dalam banyak kode peringatan hilang dalam kebisingan. Juga, ada banyak kode yang melakukan penugasan dalam ekspresi if dan banyak yang akan berpendapat bahwa itu adalah gaya yang "baik" yang valid.
Doug T.
62

Sepertinya setiap kali saya menandai sesuatu sebagai const, saya mendapatkan kesalahan dan harus mengubah beberapa fungsi lain menjadi const juga. Maka ini menyebabkan saya harus mengubah fungsi lain di tempat lain. Apakah ini sesuatu yang semakin mudah dengan pengalaman?

Dari pengalaman, ini adalah mitos total. Itu terjadi ketika non-benar-benar duduk dengan kode benar-benar, benar. Jika Anda merancang const-correct dari awal, ini TIDAK PERNAH akan menjadi masalah. Jika Anda membuat sesuatu const, dan sesuatu yang lain tidak bermasalah, kompiler memberi tahu Anda sesuatu yang sangat penting, dan Anda harus meluangkan waktu untuk memperbaikinya dengan benar .

Chris Mayer
sumber
7
Ini telah membantu saya mencegah begitu banyak bug di mana saya memiliki fungsi const akan memanggil fungsi non-const karena saya lupa itu memodifikasi data di bawahnya.
Mooing Duck
9
Sangat sedikit orang yang selalu memulai dengan basis kode yang bersih. Kebanyakan pengkodean adalah pemeliharaan kode warisan, di mana komentar yang dikutip cukup akurat. Saya menggunakan const ketika menulis fungsi daun baru, tetapi saya mempertanyakan apakah perlu mengejar hal-hal melalui setengah lusin atau selusin tingkat panggilan kode asing.
Warren Dew
3
Ini benar-benar salah dalam pengalaman saya. Jenis-jenis titik bersarang menciptakan sakit kepala terbesar untuk hal semacam ini, di mana Anda dapat memiliki beberapa const-quantifiers dalam satu jenis.
Noldorin
4
"Jika Anda merancang const-correct dari awal," berapa kali Anda benar-benar memiliki kemewahan memaksa const-correctness sejak awal ?? Sebagian besar dari kita harus berurusan dengan banyak API dan pustaka pada basis harian di mana ini tidak terjadi dan ada sedikit yang dapat Anda lakukan tentang itu. Jadi saya setuju dengan sentimen OP "Sepertinya setiap kali saya menandai sesuatu sebagai const, saya mendapatkan kesalahan" ...
nyholku
@ WarrenDew Itu argumen transitif; jika penulis asli telah menggunakan constdengan benar (yaitu "dari awal") maka memang tidak akan ada masalah, yang merupakan intinya!
Lightness Races in Orbit
31

Ini bukan untuk Anda ketika Anda menulis kode pada awalnya. Ini untuk orang lain (atau Anda beberapa bulan kemudian) yang sedang melihat deklarasi metode di dalam kelas atau antarmuka untuk melihat apa yang dilakukannya. Tidak memodifikasi objek adalah informasi penting yang dapat diperoleh dari itu.

Antonio Haley
sumber
1
Ini hanya benar. Const digunakan sebagai perlindungan juga untuk menegakkan in-variable melalui antarmuka dan sebagainya.
Jordan Parmer
Ya, tetapi Anda dapat menegakkannya melalui praktik pengkodean yang disiplin, dan poster menyatakan. Manfaat nyata berasal dari ini yang tercermin dalam API.
Antonio Haley
2
Persis. Lebih baik memiliki "const int Value = 5;" daripada memiliki "int ConstValue = 5;". +1.
paercebal
6
Waktu yang tepat untuk memasukkan const-correctness adalah ketika Anda menulis API pada awalnya. Kalau tidak, Anda akan mendapat masalah dengan keracunan const ketika Anda retrofit (itulah sebabnya menambahkannya ke kode lama adalah hal yang sama sekali berbeda dengan melakukannya dalam kode baru).
Donal Fellows
@DonalFellows ini tidak mengatakan dimasukkan ke dalam const nanti. Dikatakan bahwa Anda mendapatkan manfaat nanti, ketika Anda membaca kode dengan const sudah ada
Caleth
27

Jika Anda menggunakan const secara ketat, Anda akan terkejut betapa sedikit variabel nyata yang ada di sebagian besar fungsi. Seringkali tidak lebih dari penghitung lingkaran. Jika kode Anda mencapai titik itu, Anda mendapatkan perasaan hangat di dalam ... validasi dengan kompilasi ... ranah pemrograman fungsional terdekat ... Anda hampir dapat menyentuhnya sekarang ...

QBziZ
sumber
1
sejak C ++ 17 dan kebaikan constexpr saya menulis kompilasi tes unit waktu ... semakin dekat masih ...
QBziZ
22

const adalah janji yang Anda buat sebagai pengembang, dan meminta bantuan kompiler dalam menegakkan.

Alasan saya untuk menjadi benar-benar:

  • Ini berkomunikasi dengan klien dari fungsi Anda bahwa Anda tidak akan mengubah variabel atau objek
  • Menerima argumen dengan referensi const memberi Anda efisiensi lewat referensi dengan keamanan lewat nilai.
  • Menulis antarmuka Anda sebagai const benar akan memungkinkan klien untuk menggunakannya. Jika Anda menulis antarmuka untuk menerima referensi non-const, klien yang menggunakan const perlu membuang constness agar dapat bekerja dengan Anda. Ini sangat menjengkelkan jika antarmuka Anda menerima char * non-const, dan klien Anda menggunakan std :: strings, karena Anda hanya bisa mendapatkan char char * dari mereka.
  • Menggunakan const akan meminta kompilator menjaga Anda jujur ​​sehingga Anda tidak salah mengubah sesuatu yang seharusnya tidak berubah.
JohnMcG
sumber
20

Filosofi saya adalah bahwa jika Anda akan menggunakan bahasa rewel pada waktu kompilasi cek daripada memanfaatkan sebaik mungkin Anda bisa. constadalah cara kompiler untuk mengkomunikasikan apa yang Anda maksud ... lebih baik daripada komentar atau doxygen. Anda membayar harganya, mengapa tidak mendapatkan nilainya?

Pat Notz
sumber
20

Pemrograman C ++ tanpa const sama seperti mengemudi tanpa sabuk pengaman.

Sungguh menyakitkan memasang sabuk pengaman setiap kali Anda masuk ke mobil, dan 364 dari 365 hari Anda akan tiba dengan selamat.

Satu-satunya perbedaan adalah bahwa ketika Anda mendapat masalah dengan mobil Anda, Anda akan segera merasakannya, sedangkan dengan pemrograman tanpa const Anda mungkin harus mencari dua minggu apa yang menyebabkan kecelakaan itu hanya untuk mengetahui bahwa Anda secara tidak sengaja mengacaukan argumen fungsi yang Anda melewati referensi non-const untuk efisiensi.

andreas buykx
sumber
18

Untuk pemrograman tertanam, menggunakan secara constbijaksana ketika mendeklarasikan struktur data global dapat menghemat banyak RAM dengan menyebabkan data konstan berada di ROM atau flash tanpa menyalin ke RAM pada saat boot.

Dalam pemrograman sehari-hari, menggunakan constdengan hati - hati membantu Anda menghindari menulis program yang macet atau berperilaku tak terduga karena mereka mencoba untuk memodifikasi string string dan data global konstan lainnya.

Ketika bekerja dengan programmer lain pada proyek besar, menggunakan constdengan benar membantu mencegah programmer lain mencekik Anda.

bk1e
sumber
13

constmembantu Anda mengisolasi kode yang "mengubah sesuatu" di belakang Anda. Jadi, di kelas, Anda akan menandai semua metode yang tidak mengubah status objek sebagai const. Ini berarti bahwa constinstance dari kelas itu tidak akan lagi dapat memanggil constmetode apa pun . Dengan cara ini, Anda terhindar dari fungsi panggilan yang tidak sengaja yang dapat mengubah objek Anda.

Juga, constmerupakan bagian dari mekanisme kelebihan beban, sehingga Anda dapat memiliki dua metode dengan tanda tangan yang identik, tetapi satu dengan constdan satu tanpa. Yang satu constdipanggil untuk constreferensi, dan yang satu dipanggil untuk yang bukan constreferensi.

Contoh:

#include <iostream>

class HelloWorld {
    bool hw_called;

public:
    HelloWorld() : hw_called(false) {}

    void hw() const {
        std::cout << "Hello, world! (const)\n";
        // hw_called = true;  <-- not allowed
    }

    void hw() {
        std::cout << "Hello, world! (non-const)\n";
        hw_called = true;
    }
};

int
main()
{
    HelloWorld hw;
    HelloWorld* phw1(&hw);
    HelloWorld const* phw2(&hw);

    hw.hw();    // calls non-const version
    phw1->hw(); // calls non-const version
    phw2->hw(); // calls const version
    return 0;
}
Chris Jester-Young
sumber
13

kebenaran konst adalah salah satu hal yang benar-benar harus ada sejak awal. Seperti yang telah Anda temukan, sangat sulit untuk menambahkannya nanti, terutama ketika ada banyak ketergantungan antara fungsi baru yang Anda tambahkan dan fungsi lama yang tidak benar yang sudah ada.

Dalam banyak kode yang saya tulis, itu benar-benar sepadan dengan usaha karena kita cenderung menggunakan banyak komposisi:

class A { ... }
class B { A m_a; const A& getA() const { return m_a; } };

Jika kami tidak memiliki const-correctness, maka Anda harus menggunakan mengembalikan objek kompleks dengan nilai untuk meyakinkan diri sendiri bahwa tidak ada yang memanipulasi keadaan internal kelas B di belakang Anda.

Singkatnya, const-correctness adalah mekanisme pemrograman defensif untuk menyelamatkan diri dari rasa sakit di jalan.

Peter Kovacs
sumber
7

Katakanlah Anda memiliki variabel dalam Python. Anda tahu Anda tidak harus memodifikasinya. Bagaimana jika Anda tidak sengaja melakukannya?

C ++ memberi Anda cara untuk melindungi diri dari melakukan sesuatu yang tidak seharusnya Anda lakukan sejak awal. Secara teknis Anda bisa menyiasatinya, tetapi Anda harus bekerja ekstra untuk menembak diri sendiri.

Greg Rogers
sumber
4

Ada artikel yang bagus di sini tentang const di c ++. Pendapatnya cukup lurus ke depan tapi semoga membantu.

Ólafur Waage
sumber
3

Saat Anda menggunakan kata kunci "const", Anda menentukan antarmuka lain untuk kelas Anda. Ada antarmuka yang mencakup semua metode, dan antarmuka yang hanya mencakup metode const. Jelas ini memungkinkan Anda membatasi akses ke beberapa hal yang tidak ingin Anda ubah.

Ya, memang semakin mudah seiring waktu.

Wesley Tarle
sumber
2

Saya suka benar const ... dalam teori. Setiap kali saya mencoba untuk menerapkannya dengan ketat dalam prakteknya akhirnya telah rusak dan const_cast mulai merayap dalam membuat kode jelek.

Mungkin itu hanya pola desain yang saya gunakan, tetapi const selalu berakhir menjadi sikat yang terlalu luas.

Misalnya, bayangkan mesin database sederhana ... ia memiliki objek skema, tabel, bidang dll. Seorang pengguna mungkin memiliki pointer 'const Table' yang berarti bahwa mereka tidak diizinkan untuk memodifikasi skema tabel itu sendiri ... tetapi bagaimana dengan memanipulasi data yang terkait dengan tabel? Jika metode Insert () ditandai const, maka secara internal harus membuang konstanta untuk benar-benar memanipulasi database. Jika tidak ditandai const maka itu tidak melindungi terhadap memanggil metode AddField.

Mungkin jawabannya adalah untuk membagi kelas berdasarkan persyaratan konstan, tetapi itu cenderung mempersulit desain lebih daripada yang saya inginkan untuk manfaat yang dibawanya.

Rob Walker
sumber
Saya pikir contoh Anda adalah kasus penggunaan const yang terlalu banyak, tetapi jangan lupa tentang pengubah yang bisa berubah-ubah, yang dapat diterapkan pada variabel instan untuk menghapus konstanta.
Zooba
2
Kapan fungsi Sisipkan () akan ditandai sebagai konst kecuali jika salah namanya? Menambahkan hal-hal biasanya mengubah hal yang Anda tambahkan, artinya bukan konstanta. Apa yang benar-benar Anda inginkan adalah TableWithConstSchema.
Greg Rogers
Saya bisa menambahkan kelas lain, tetapi saya tidak ingin membuat API tidak perlu menjadi murni semata-mata demi kebenaran konst.
Rob Walker
1

Anda dapat memberikan petunjuk compiler dengan const juga .... sesuai kode berikut

#include <string>

void f(const std::string& s)
{

}
void x( std::string& x)
{
}
void main()
{
    f("blah");
    x("blah");   // won't compile...
}
Keith Nicholas
sumber