Apakah const_cast aman?

92

Saya tidak dapat menemukan banyak informasi tentang const_cast. Satu-satunya info yang dapat saya temukan (di Stack Overflow) adalah:

Yang const_cast<>()digunakan untuk menambah / menghapus const (an) (atau volatil-an) dari variabel.

Ini membuatku gugup. Bisakah menggunakan const_castpenyebab perilaku yang tidak terduga? Jika ya, apa?

Atau, kapan boleh digunakan const_cast?

Mag Roader
sumber
4
Jawaban teratas mengabaikan sesuatu yang mungkin sangat jelas tetapi layak untuk dinyatakan: Ini hanya menjadi tidak aman jika Anda mencoba untuk memodifikasi constobjek aslinya melalui constreferensi / penunjuk de- ed. Sebaliknya, jika Anda hanya const_castingin bekerja di sekitar API dengan spesifikasi yang buruk (atau, dalam kasus saya, malas) yang hanya menerima non- constreferensi tetapi hanya akan digunakan dalam constmetode ... tidak ada masalah sama sekali.
underscore_d
1
@underscore_d: Sebuah versi yang lebih tepat dari pertanyaan (dan jawaban) yang meliputi: Apakah diperbolehkan untuk membuang const pada objek yang ditentukan const selama tidak benar-benar dimodifikasi?
Peter Cordes

Jawaban:

89

const_castaman hanya jika Anda mentransmisikan variabel yang awalnya bukan- const. Misalnya, jika Anda memiliki fungsi yang mengambil parameter a const char *, dan Anda meneruskan sebuah modifiable char *, maka aman untuk const_castparameter itu kembali ke a char *dan memodifikasinya. Namun, jika variabel aslinya ternyata const, maka penggunaan const_castakan menghasilkan perilaku yang tidak terdefinisi.

void func(const char *param, size_t sz, bool modify)
{
    if(modify)
        strncpy(const_cast<char *>(param), sz, "new string");
    printf("param: %s\n", param);
}

...

char buffer[16];
const char *unmodifiable = "string constant";
func(buffer, sizeof(buffer), true);  // OK
func(unmodifiable, strlen(unmodifiable), false); // OK
func(unmodifiable, strlen(unmodifiable), true);  // UNDEFINED BEHAVIOR
Adam Rosenfield
sumber
9
Itu tidak benar. Standar C ++. §7.1.​5.1/4 says Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior Upaya apa pun ! Tidak ada kata-kata tentang variabel asli.
Alexey Malistov
20
@Alexey: Variabel asli adalah tentang apa yang diarahkan atau dirujuk. Anda dapat mengambil referensi const ke objek non-const, dan oleh karena itu, mentransmisikannya ke referensi yang dapat ditulis adalah perilaku yang terdefinisi dengan baik karena objek yang dirujuk sebenarnya bukan konst.
Anak anjing
43
@Alexey Malistov: Tidak. "Objek" merujuk ke wilayah penyimpanan aktual yang ditempati dalam memori (§1.7). Mengambil referensi const ke objek non-const tidak membuat objek tersebut menjadi const. Hanya dalam kasus parameter referensi const ( bukan parameter pointer const) kompilator diperbolehkan untuk membuat salinan secara diam-diam (§5.2.2 / 5); ini tidak terjadi di sini.
Adam Rosenfield
8
"Namun, jika variabel asli sebenarnya adalah const, maka menggunakan const_cast akan menghasilkan perilaku tidak terdefinisi" Pernyataan ini salah.
Balapan Ringan di Orbit
7
Ini tidak UB untuk menggunakan const_castuntuk menghapus constdari sesuatu yang awalnya dinyatakan const. Tapi itu adalah UB untuk benar-benar mencoba untuk menulis ke objek. Selama Anda baru saja membaca Anda baik-baik saja dan const_castitu sendiri tidak menyebabkan UB. Itu ide yang buruk, tapi itu bukan UB secara inheren.
Jesper Juhl
35

Saya dapat memikirkan dua situasi di mana const_cast aman dan berguna (mungkin ada kasus valid lainnya).

Salah satunya adalah ketika Anda memiliki instance, referensi, atau pointer const, dan Anda ingin meneruskan pointer atau referensi ke API yang tidak benar, tetapi Anda TERTENTU tidak akan mengubah objek. Anda dapat const_cast penunjuk dan meneruskannya ke API, percaya bahwa itu tidak akan benar-benar mengubah apa pun. Sebagai contoh:

void log(char* text);   // Won't change text -- just const-incorrect

void my_func(const std::string& message)
{
    log(const_cast<char*>(&message.c_str()));
}

Yang lainnya adalah jika Anda menggunakan kompiler lama yang tidak mengimplementasikan 'mutable', dan Anda ingin membuat kelas yang secara logis const tetapi bukan const bitwise. Anda bisa const_cast 'this' dalam metode const dan memodifikasi anggota kelas Anda.

class MyClass
{
    char cached_data[10000]; // should be mutable
    bool cache_dirty;        // should also be mutable

  public:

    char getData(int index) const
    {
        if (cache_dirty)
        {
          MyClass* thisptr = const_cast<MyClass*>(this);
          update_cache(thisptr->cached_data);
        }
        return cached_data[index];
    }
};
Fred Larson
sumber
Ini ... sepertinya tidak menjawab pertanyaan ini. Dia bertanya apakah const_castdapat menyebabkan perilaku yang tidak terdefinisi, bukan aplikasi berguna apa darinya
Michael Mrozek
13
Dari pertanyaan: "Atau, kapan boleh menggunakan const_cast?"
Fred Larson
Seperti dalam "when is not undefined"; dia tidak mencari contoh kapan itu berguna
Michael Mrozek
Kami hanya bisa menempel pada huruf pertanyaan. Berdasarkan hal tersebut, penyajian penggunaan ilustratif const_castmerupakan jawaban yang valid. Tidak ada hepertanyaan karena pertanyaannya sendiri adalah subjeknya.
eigenfield
24

Saya merasa sulit untuk percaya bahwa itulah satu - satunya informasi yang dapat Anda temukan tentang const_cast. Mengutip dari hit Google kedua :

Jika Anda membuang konstanta objek yang telah dideklarasikan secara eksplisit sebagai const, dan mencoba untuk memodifikasinya, hasilnya tidak akan ditentukan.

Namun, jika Anda membuang konstanta objek yang belum dideklarasikan secara eksplisit sebagai const, Anda dapat memodifikasinya dengan aman.

Rob Kennedy
sumber
Grrrrreaat jawaban, gabungkan ini dengan jawaban ini dan Anda mendapatkan gambaran keseluruhan.
bobobobo
hmm. mengenai pernyataan kedua dalam jawaban Anda, bolehkah saya bertanya kepada Anda bagaimana ada "konstanta" untuk objek yang tidak secara eksplisit dideklarasikan sebagai const di tempat pertama ?.
hAcKnRoCk
Ada banyak cara untuk membuat objek non-const menjadi const, @Iam. Misalnya, teruskan objek sebagai parameter referensi-konst. Atau tetapkan ke pointer-to-const. Atau gunakan const_cast. Atau panggil metode const di atasnya.
Rob Kennedy
12

Apa yang Adam katakan. Contoh lain di mana const_cast dapat membantu:

struct sample {
    T& getT() { 
        return const_cast<T&>(static_cast<const sample*>(this)->getT()); 
    }

    const T& getT() const { 
       /* possibly much code here */
       return t; 
    }

    T t;
};

Pertama kita menambahkan const ke tipe thispoin ke, lalu kami memanggil versi const getT, dan kemudian kami menghapus const dari tipe kembalian, yang valid karena tharus non-const (jika tidak, versi non-konst dari getTtidak dapat memiliki telah dipanggil). Ini bisa sangat berguna jika Anda memiliki badan fungsi yang besar dan Anda ingin menghindari kode yang berlebihan.

Johannes Schaub - litb
sumber
3
Saya lebih suka menggunakan cast statis untuk menambahkan constness: static_cast <const sample *> (ini). Ketika saya membaca const_cast itu berarti bahwa kode tersebut melakukan sesuatu yang berpotensi berbahaya, jadi saya mencoba untuk menghindari penggunaannya bila memungkinkan.
mfazekas
1
benar, yang pertama bisa berupa static_cast, atau bahkan implicit_cast (dari boost). saya akan memperbaikinya menggunakan cast statis. terima kasih
Johannes Schaub - litb
3
Saya bolak-balik menanyakan apakah lebih baik const_castatau static_castlebih. const_casthanya dapat melakukan apa yang Anda inginkan: ubah cv-qualifier. static_castdapat 'diam-diam' melakukan operasi lain yang tidak Anda inginkan. Namun, pemeran pertama sepenuhnya aman, dan static_castcenderung lebih aman daripada const_cast. Saya pikir ini adalah situasi di mana const_castmengkomunikasikan niat Anda dengan lebih baik, tetapi static_castmengkomunikasikan keamanan tindakan Anda dengan lebih baik.
David Stone
10

Jawaban singkatnya adalah tidak, ini tidak aman.

Jawaban panjangnya adalah jika Anda cukup tahu untuk menggunakannya, maka itu harus aman.

Saat Anda mentransmisi, yang pada dasarnya Anda katakan adalah, "Saya tahu sesuatu yang tidak diketahui kompilator." Dalam kasus const_cast, yang Anda katakan adalah, "Meskipun metode ini menggunakan referensi atau penunjuk non-const, saya tahu bahwa itu tidak akan mengubah parameter yang saya berikan."

Jadi jika Anda benar-benar tahu apa yang Anda klaim tahu dalam menggunakan pemeran, maka tidak masalah untuk menggunakannya.

JohnMcG
sumber
4

Anda menghancurkan peluang keamanan thread, jika Anda mulai memodifikasi hal-hal yang menurut compiler adalah const.

Matt Cruikshank
sumber
1
Apa? Jika Anda memiliki berubah (const) objek, Anda dapat sepele berbagi mereka di antara benang. Saat sebagian kode Anda membuang konstanta, Anda kehilangan semua keamanan utas Anda! Mengapa saya down-modded untuk ini? menghela napas
Matt Cruikshank
9
Const jelas merupakan alat yang berguna dalam membuat kode aman untuk thread, tetapi tidak memberikan jaminan (kecuali dalam kasus konstanta waktu kompilasi). Dua contoh: sebuah objek const mungkin memiliki anggota yang bisa berubah, dan memiliki pointer const ke sebuah objek tidak mengatakan apa-apa tentang apakah objek itu sendiri dapat berubah.
James Hopkin
Saya rasa ini adalah jawaban yang bagus karena saya tidak memikirkan tentang perasaan kepercayaan dan keamanan pengoptimal kompiler dalam penggunaan kata tersebut const. constadalah kepercayaan. const_castmelanggar kepercayaan itu :(
bobobobo
1
Mengenai mutable dan thread-safety: channel9.msdn.com/posts/…
MFH