Apa gunanya pointer pointer?

149

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?

R. Ruiz.
sumber
29
Bagaimana jika Anda ingin menjamin, pada waktu kompilasi, bahwa pointer tidak dapat dan tidak boleh dimodifikasi untuk menunjuk ke hal lain?
Platinum Azure
25
Persis sama dengan constparameter apa pun .
David Heffernan
2
@PlatinumAzure, saya memiliki beberapa tahun pengalaman pemrograman, namun praktik perangkat lunak saya kurang. Saya senang saya membuat pertanyaan ini karena saya tidak pernah merasa perlu untuk membuat kompiler menunjukkan kesalahan logika saya sendiri. Reaksi awal saya pada saat saya mengajukan pertanyaan adalah "mengapa saya harus peduli jika pointer diubah ?, itu tidak akan mempengaruhi pemanggil". Sampai saya membaca semua jawaban saya mengerti bahwa saya harus peduli karena jika saya mencoba untuk memodifikasinya, saya dan logika kode saya salah (atau ada kesalahan ketik seperti asterisk yang hilang) dan saya mungkin tidak menyadari jika kompiler tidak melakukannya t memberitahuku.
R. Ruiz.
3
@RRiz. Tidak diragukan lagi, bahkan yang paling berpengalaman dari kita dapat melakukannya dengan jaminan kebenaran tambahan. Karena rekayasa perangkat lunak adalah suatu bentuk rekayasa di mana sedikit lebih banyak kelonggaran dapat diterima (HTTP 502s acak, koneksi lambat, gambar sesekali gagal dimuat bukan peristiwa yang luar biasa, tetapi mesin yang gagal di pesawat tidak dapat diterima dan cenderung parah), kadang-kadang Program orang dengan tergesa-gesa yang tidak semestinya. Argumen yang sama yang membenarkan tes unit tulisan akan menjelaskan penggunaan constjaminan -koreksi. Itu hanya membuat kita merasa lebih yakin bahwa kode kita pasti benar.
Platinum Azure
3
Sebuah pertanyaan terkait: stackoverflow.com/questions/219914/…
Raedwald

Jawaban:

207

const adalah alat yang harus Anda gunakan dalam mengejar konsep C ++ yang sangat penting:

Temukan bug pada waktu kompilasi, bukan pada waktu berjalan, dengan meminta kompiler untuk menegakkan apa yang Anda maksud.

Meskipun itu tidak mengubah fungsionalitas, menambahkan constmenghasilkan kesalahan kompiler ketika Anda melakukan hal-hal yang tidak ingin Anda lakukan. Bayangkan salah ketik berikut:

void foo(int* ptr)
{
    ptr = 0;// oops, I meant *ptr = 0
}

Jika Anda menggunakan int* const, ini akan menghasilkan kesalahan kompiler karena Anda mengubah nilainya menjadi ptr. 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 menggunakannya const.

sepuluh empat
sumber
8
Terima kasih, ini adalah jawaban yang meyakinkan saya. Anda meletakkan const sehingga kompiler memperingatkan Anda tentang kesalahan tugas Anda sendiri. Contoh Anda sempurna untuk menggambarkan konsep ini karena itu adalah kesalahan umum dengan petunjuk. Daripada Anda!
R. Ruiz.
25
"Bantu kompiler membantu Anda" adalah mantra yang biasanya saya nyanyikan untuk ini.
Flexo
1
+1, tapi di sini ada kasus menarik yang bisa diperdebatkan: stackoverflow.com/questions/6305906/…
Raedwald
3
jadi itu adalah jawaban yang sama yang akan Anda berikan kepada "Mengapa membuat variabel pribadi, ketika Anda tidak bisa menggunakannya di luar kelas."
Lee Louviere
ini mungkin sedikit di luar topik, tetapi di mana pointer const duduk di memori? Saya tahu semua const duduk di bagian global memori, tetapi saya tidak 100% yakin tentang const bahwa Anda bisa lulus sebagai func var. terima kasih dan maaf jika ini di luar topik
Tomer
77

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 mana constakan 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 constparameter di dalam fungsi.

Contoh:

// foo.h
int frob(int x);
// foo.cpp
int frob(int const x) {
   MyConfigType const config = get_the_config();
   return x * config.scaling;
}

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.

Konrad Rudolph
sumber
17
+1dari constfanatik -sesuai lain . Namun, saya lebih suka kompiler saya untuk menyalak. Saya membuat terlalu banyak kesalahan dan akan sangat menderita jika mereka menggigit.
sbi
2
+1, saya sangat merekomendasikan strategi " constkecuali ada alasan bagus". Ada beberapa pengecualian, misalnya Salin dan tukar
Flexo
2
Jika saya mendesain bahasa baru, objek yang dideklarasikan akan menjadi read-only ("const") secara default. Anda memerlukan beberapa sintaks khusus, mungkin kata kunci "var", untuk membuat objek dapat ditulis.
Keith Thompson
@Keith saya tergoda untuk mengatakan "tentu saja". Yang lainnya bodoh pada saat ini. Namun sayangnya sebagian besar perancang bahasa tampaknya tidak setuju dengan kami ... Bahkan, saya sudah memposting sebanyak itu (dalam pertanyaan yang sekarang dihapus, "Apa pendapat Anda tentang pemrograman yang paling kontroversial?").
Konrad Rudolph
1
@ KubaOber Saya tidak melihat bagaimana itu pesimis sama sekali. Jika nanti Anda menemukan bahwa Anda perlu memodifikasi apa yang telah diteruskan di dalam tubuh fungsi, maka cukup lepaskan constdari argumen, dan lebih baik berikan komentar mengapa. Sedikit kerja ekstra itu tidak membenarkan menandai semua argumen sebagai tidak- constbaku dan membuka diri terhadap semua potensi kesalahan yang terjadi.
underscore_d
20

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:

void foo(T);

Ini sepenuhnya tergantung pada pelaksana fungsi apakah dia ingin menggunakan variabel argumen fungsi-lingkup dalam bisa berubah atau dengan cara yang konstan:

// implementation 1
void foo(T const x)
{
  // I won't touch x
  T y = x;
  // ...
}

// implementation 2
void foo(T x)
{
  // l33t coding skillz
  while (*x-- = zap()) { /* ... */ }
}

Jadi, ikuti aturan sederhana untuk tidak pernah memasukkan constdeklarasi (header), dan memasukkannya ke dalam definisi (implementasi) jika Anda tidak ingin atau perlu memodifikasi variabel.

Kerrek SB
sumber
5
Saya setuju dengan ini - tapi saya agak tidak nyaman dengan gagasan untuk membuat deklarasi dan definisi berbeda. Untuk hal-hal selain const, deklarasi dan (bagian prototipe) definisi umumnya akan sama.
Keith Thompson
@KeithThompson: Ya, Anda tidak harus melakukannya jika tidak mau. Hanya saja, jangan dimasukkan constdalam deklarasi. Ini sepenuhnya terserah Anda jika Anda ingin menambahkan kualifikasi dalam implementasi.
Kerrek SB
1
Seperti yang saya katakan, saya setuju bahwa meletakkan constdeklarasi 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.)
Keith Thompson
16

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.

David Rodríguez - dribeas
sumber
Saya tidak tahu itu. Jadi jika saya mencoba untuk membebani void foo (int * const ptr) dengan void foo (int * t ptr) saya akan mendapatkan kesalahan kompiler. Terima kasih!
R. Ruiz.
@RRiz. Jika deselerasi Anda adalah void foo (int * t ptr) dan definisi Anda adalah void foo (int * const ptr), Anda TIDAK akan mendapatkan kesalahan kompiler.
Trevor Hickey
1
@ TrevorHickey Mereka akan ... tetapi tidak karena alasan yang mereka pikirkan. int* t ptradalah kesalahan sintaksis. Tanpa itu, keduanya identik untuk tujuan overloading.
underscore_d
14

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 = 42dalam program Anda.

cnicutar
sumber
1
Apa bedanya di mana mereka mengarahkannya, itu adalah pointer yang dialokasikan pada stack? Fungsi tidak dapat mengacaukannya. Jauh lebih masuk akal untuk menggunakan pointer read-only ketika berhadapan dengan pointer-to-pointer. Ini tidak sama dengan int const! Saya akan menurunkan ini hanya untuk pernyataan yang menyesatkan itu. const intdan int constsetara, sementara const int*dan int* constmemiliki dua arti berbeda!
Lundin
1
@ Lundin Anggap saja fungsinya besar dan ada hal-hal lain di dalamnya. Secara tidak sengaja seseorang dapat mengarahkannya ke sesuatu yang lain (pada tumpukan fungsi). Ini tidak bermasalah untuk penelepon tetapi tentu bisa untuk callee. Saya tidak melihat sesuatu yang menyesatkan dalam pernyataan saya: " bagi penulis fungsi itu bisa menjadi jaring pengaman".
cnicutar
1
@Lundin Tentang int constbagian; 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.
cnicutar
1
Baik. Saya baru saja menulis jawaban panjang lebar saya sendiri kalau-kalau ada orang lain tetapi Anda dan saya membaca posting ini. Saya juga menyertakan alasan mengapa int const adalah gaya yang buruk dan const int adalah gaya yang baik.
Lundin
Lundin, aku juga membaca! Saya setuju bahwa const int adalah gaya yang lebih baik. @cnicutar, respons pertama Anda terhadap Lundin adalah apa yang saya cari ketika saya mengirimkan pertanyaan ini. Jadi masalahnya bukan pada penelepon (seperti yang saya pikirkan tanpa berpikir), tetapi const adalah jaminan bagi callee. Saya suka ide ini, terima kasih.
R. Ruiz.
14

Ada banyak constkata 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 volatiledan restrict. 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 constkata kunci:

Deklarasikan variabel konstan.

Ini dapat dilakukan sebagai

const int X=1; or
int const X=1;

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 staticdll. 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.

const int* ptr = &X;

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

int* const ptr = &X;

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:

void func (int*const* ptrptr)

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

const int* const ptr=&X;

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:

void MyClass::func (void) const;
Lundin
sumber
8

... hari ini saya menyadari bahwa pointer diteruskan oleh nilai ke fungsi, yang masuk akal.

(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.

Jadi apa kelebihan const?

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:

void func(int* const arg) {
    int* a(arg);
    ...
    *a++ = value;
}

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.

justin
sumber
4
+1 untuk ini menjadi default. C ++, seperti kebanyakan bahasa, memiliki cara yang salah. Alih-alih memiliki constkata kunci, itu harus memiliki mutablekata kunci (well, ia memiliki, tetapi dengan semantik yang salah).
Konrad Rudolph
2
Ide yang menarik memiliki const sebagai default. Terima kasih atas jawaban anda!
R. Ruiz.
6

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;

Dan Haynes
sumber
5

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

jusathr
sumber
5

Pertanyaan yang sama dapat ditanyakan tentang jenis lain (bukan hanya petunjuk):

/* Why is n const? */
const char *expand(const int n) {
    if (n == 1) return "one";
    if (n == 2) return "two";
    if (n == 3) return "three";
    return "many";
}
pmg
sumber
LOL, kamu benar. Kasus petunjuk datang ke pikiran saya pertama karena saya pikir mereka istimewa, tetapi mereka sama seperti variabel lain yang dilewati oleh nilai.
R. Ruiz.
5

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.

zar
sumber
komentar Anda membuat menyadari betapa sia-sianya pertanyaan saya karena Anda benar: itu sama dengan memiliki parameter lain sebagai const. Ini mungkin tampak tidak berguna tetapi ada di sana untuk membantu programmer memiliki batasan ini dan menghindari bug
R. Ruiz.
4

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.

Anders Abel
sumber
4

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.

MartinStettner
sumber
+1 untuk optimisasi. Setidaknya buku-buku itu mengatakan itu benar. Yang saya inginkan adalah untuk memahami apa sebenarnya optimasi itu
R. Ruiz.
4

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:

#include <new>
#include <string.h>

class TestA
{
    private:
        char *Array;
    public:
        TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
        ~TestA(){if(Array != NULL){ delete [] Array;} }

        char * const GetArray(){ return Array; }
};

int main()
{
    TestA Temp;
    printf("%s\n",Temp.GetArray());
    Temp.GetArray()[0] = ' '; //You can still modify the chars in the array, user has access
    Temp.GetArray()[1] = ' '; 
    printf("%s\n",Temp.GetArray());
}

Yang menghasilkan:

Input data
memasukkan data

Tetapi jika kita coba ini:

int main()
{
    TestA Temp;
    printf("%s\n",Temp.GetArray());
    Temp.GetArray()[0] = ' ';
    Temp.GetArray()[1] = ' ';
    printf("%s\n",Temp.GetArray());
    Temp.GetArray() = NULL; //Bwuahahahaa attempt to set it to null
}

Kita mendapatkan:

error: nilai diperlukan sebagai operan tugas kiri // Drat digagalkan lagi!

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:

int main()
{
    TestA Temp;
    printf("%s\n",Temp.GetArray());
    Temp.GetArray()[0] = ' ';
    Temp.GetArray()[1] = ' ';
    printf("%s\n",Temp.GetArray());
    delete [] Temp.GetArray(); //Bwuahaha this actually works!
}

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:

class TestA
{
    private:
        char *Array;
    public:
        TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
        ~TestA(){if(Array != NULL){ delete [] Array;} }

        char * const &GetArray(){ return Array; } //Note & reference operator
        char * &GetNonConstArray(){ return Array; } //Note non-const
};

int main()
{
    TestA Temp;
    Temp.GetArray() = NULL; //Returns error
    Temp.GetNonConstArray() = NULL; //Returns no error
}

Akan kembali yang pertama menghasilkan kesalahan:

galat: penugasan lokasi hanya baca 'Temp.TestA :: GetArray ()'

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):

class TestA
{
    private:
        char *Array;
    public:
        TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
        ~TestA(){if(Array != NULL){ delete [] Array;} }

        char * const &GetArray(){ return Array; }

        void ModifyArrayConst(char * const Data)
        {
            Data[1]; //This is okay, this refers to Data[1]
            Data--; //Produces an error. Don't want to Decrement that.
            printf("Const: %c\n",Data[1]);
        }

        void ModifyArrayNonConst(char * Data)
        {
            Data--; //Argh noo what are you doing?!
            Data[1]; //This is actually the same as 'Data[0]' because it's relative to Data's position
            printf("NonConst: %c\n",Data[1]);
        }
};

int main()
{
    TestA Temp;
    Temp.ModifyArrayNonConst("ABCD");
    Temp.ModifyArrayConst("ABCD");
}

Kesalahan dalam const menghasilkan pesan:

kesalahan: penurunan 'data' hanya baca parameter

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:

NonConst: A
Const: B

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:

int main()
{
    int A = 10;
    int * const B = &A;
    *B = 20; //This is permitted
    printf("%d\n",A);
    B = NULL; //This produces an error
}

Ketika mencoba mengkompilasi, menghasilkan kesalahan berikut:

kesalahan: penugasan variabel hanya baca 'B'

Yang mungkin merupakan hal yang buruk jika referensi konstan ke A diinginkan. Jika B = NULLdikomentari, 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.

SSight3
sumber
2
Temp.GetArray() = NULLgagal karena Temp.GetArray()merupakan nilai, bukan karena memenuhi syarat. Selain itu, saya percaya const-kualifikasi dilepaskan dari semua tipe pengembalian.
Oscar Korz
@ okorz001: Setelah pengujian, Anda memang benar. Namun, hal di atas berlaku jika Anda mengembalikan referensi ke pointer itu sendiri. Saya akan mengedit posting saya sesuai.
SSight3
3

Tidak ada yang istimewa tentang pointer di mana Anda tidak akan pernah ingin mereka menjadi const. Sama seperti Anda dapat memiliki intnilai 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.

Markus B
sumber
3

Saya percaya ini akan mencegah kode dari menambah atau mengurangi pointer di dalam fungsi body.

Mike Christensen
sumber
3

Jenis mendeklarasikan variabel seperti-
(1) Mendeklarasikan variabel konstan.
DataType const varibleName;

 int const x;
    x=4; //you can assign its value only One time
(2) Nyatakan pointer ke variabel konstan
const dataType* PointerVaribleName=&X;
 const int* ptr = &X;
     //Here pointer variable refer contents of 'X' that is const Such that its cannot be modified
dataType* const PointerVaribleName=&X;
 int* const ptr = &X;
     //Here pointer variable itself is constant  Such that value of 'X'  can be modified But pointer can't be modified

Pyadav
sumber
Kami menyediakan variabel pointer sebagai const ke fungsi sebagai argumen ketika kita tidak ingin mengubah nilai sebenarnya
Pyadav