Const_cast güvenli mi?


92

Hakkında fazla bilgi bulamıyorum const_cast. Bulabildiğim tek bilgi (Stack Overflow'da):

const_cast<>()/ Bir değişkenin kaldırma const (lık) (veya uçucu-lık) eklemek için kullanılır.

Bu beni endişelendiriyor. Bir kullanarak Could const_castnedeni beklenmeyen davranışlarla? Öyleyse ne olmuş?

Alternatif olarak, ne zaman kullanmak uygun olur const_cast?


4
En üstteki cevap, korkunç derecede açık olabilecek bir şeyi gözden kaçırır, ancak belirtmeye değer: Yalnızca orijinal bir constnesneyi , tanımlanmamış bir constreferans / işaretçi yoluyla değiştirmeye çalışırsanız, bu güvensiz hale gelir . Bunun yerine, yalnızca referans const_castolmayanı kabul eden, constancak yalnızca constyöntemlerde kullanılacak olan , yetersiz (veya benim durumumda tembel olarak) spesifik bir API etrafında çalışmak istiyorsanız ... hiçbir sorun yok.
underscore_d

1
@underscore_d: Sorunun (ve cevabın) aşağıdakileri kapsayan daha kesin bir versiyonu: Aslında değiştirilmediği sürece const tanımlı bir nesnede const
Peter Cordes

Yanıtlar:


89

const_castyalnızca orijinal olmayan bir değişkeni atıyorsanız güvenlidir const. Örneğin, bir a parametresini alan bir fonksiyonunuz varsa const char *ve bir değiştirilebilir parametresini iletirseniz char *, o const_castparametreye geri dönüp onu değiştirmek güvenlidir char *. Ancak, orijinal değişken gerçekte ise const, o zaman kullanmak const_casttanımsız davranışla sonuçlanacaktır.

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

9
Bu doğru değil. C ++ standardı. §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 Herhangi bir girişim ! Orijinal değişken hakkında hiçbir kelime yok.
Alexey Malistov

20
@Alexey: Orijinal değişken neye işaret edildiği veya neye atıfta bulunulduğu ile ilgilidir. Const olmayan bir nesneye const başvurusu alabilirsiniz ve bu nedenle, yazılabilir bir başvuruya atamak, başvurulan nesne aslında const olmadığından, iyi tanımlanmış bir davranıştır.
Puppy

43
@Alexey Malistov: Hayır. "Nesne", bellekte bulunan gerçek depolama bölgesini ifade eder (§1.7). Const olmayan bir nesneye const başvurusu almak nesneyi const yapmaz. Sadece const halinde referans parametresi ( değil const işaretçi parametresi) sessiz bir kopya (§5.2.2 / 5) yapmak için izin derleyici; burada durum böyle değil.
Adam Rosenfield

8
"Ancak, eğer orijinal değişken aslında const ise, o zaman const_cast kullanmak tanımsız davranışa neden olur" Bu ifade yanlıştır.
Orbit'te Hafiflik Yarışları

7
O var değil kullanmak UB const_castkaldırmak için constbaşlangıçta ilan edildi birşeyden const. Ama olan UB aslında nesneye yazma denemek için. Sadece okuduğunuz sürece iyisiniz ve const_castkendi başına UB'ye neden olmaz. Bu korkunç bir fikir, ama doğası gereği UB değil.
Jesper Juhl

35

Const_cast'in güvenli ve kullanışlı olduğu iki durum düşünebilirim (başka geçerli durumlar olabilir).

Birincisi, bir const örneğiniz, başvurunuz veya işaretçiniz olduğunda ve const-doğru olmayan bir API'ye bir işaretçi veya başvuru iletmek istediğinizde, ancak CERTAIN'in nesneyi değiştirmeyeceğidir. İşaretçiyi sabitleyebilir ve gerçekten hiçbir şeyi değiştirmeyeceğine güvenerek API'ye iletebilirsiniz. Örneğin:

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()));
}

Diğeri, 'mutable' uygulamayan eski bir derleyici kullanıyorsanız ve mantıksal olarak sabit olan ancak bitsel sabit olmayan bir sınıf oluşturmak istiyorsanız. Bir const yöntemi içinde "this" i sabitleyebilir ve sınıfınızın üyelerini değiştirebilirsiniz.

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];
    }
};

Bu ... bu soruyu yanıtlıyor gibi görünmüyor. const_castTanımlanmamış davranışlara neden olup olmayacağını sordu , bunun hangi yararlı uygulamaları olduğunu değil
Michael Mrozek

13
Sorudan: "Alternatif olarak, ne zaman const_cast kullanmak uygun olur?"
Fred Larson

"Ne zaman tanımsız değildir" gibi; ne zaman faydalı olacağına dair örnekler aramıyor
Michael Mrozek

Sadece sorunun harflerine bağlı kalabiliriz. Buna dayanarak, açıklayıcı bir kullanımın sunulması const_castgeçerli bir cevaptır. heKonu tek başına soru olduğu için sorularda yoktur .
eigenfield

24

Const_cast hakkında bulabileceğiniz tek bilginin bu olduğuna inanmakta zorlanıyorum. İkinci Google isabetinden alıntı :

Açıkça const olarak bildirilmiş bir nesnenin sabitliğini atarsanız ve onu değiştirmeye çalışırsanız, sonuçlar tanımsız olur.

Ancak, açık bir şekilde const olarak bildirilmemiş bir nesnenin sabitliğini atarsanız, onu güvenli bir şekilde değiştirebilirsiniz.


Grrrreaat cevap, bunu bu cevapla birleştirin ve bütün resmi elde edin.
bobobobo

hmm. Cevabınızdaki ikinci ifade ile ilgili olarak, ilk etapta açıkça const olarak bildirilmemiş bir nesne için nasıl bir "sabit" olduğunu sorabilir miyim?
hAcKnRoCk

Const olmayan bir nesneyi const, @Iam yapmanın birçok yolu vardır. Örneğin, nesneyi bir sabit başvuru parametresi olarak iletin. Veya bir işaretçi-sabit'e atayın. Veya kullanın const_cast. Veya bir const yöntemi çağırın.
Rob Kennedy

12

Adam ne diyor. Const_cast'in yardımcı olabileceği başka bir örnek:

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;
};

Önce tür thisişaretlerine const ekleriz , sonra const sürümünü çağırırız getTve sonra const'ı döndürme türünden kaldırırız, çünkü bu geçerli t, const olmayan olmalıdır (aksi takdirde, const olmayan sürüm getTolamazdı çağrıldı). Büyük bir işlev gövdeniz varsa ve gereksiz kodlardan kaçınmak istiyorsanız, bu çok yararlı olabilir.


3
Sabitlik eklemek için statik çevirmeyi tercih ederim: static_cast <const sample *> (this). Const_cast okuduğumda, kodun potansiyel olarak tehlikeli bir şey yaptığı anlamına gelir, bu yüzden mümkün olduğunda kullanılmasından kaçınmaya çalışıyorum.
mfazekas

1
doğru, ilki static_cast veya hatta implicit_cast (boost) olabilir. Statik dönüştürme kullanarak düzelteceğim. teşekkürler
Johannes Schaub - litb

3
Ben olmadığına ileri geri gitmek const_castveya static_castdaha iyidir. const_castsadece istediğinizi yapabilirsiniz: cv niteleyicilerini değiştirin. static_castsizin istemediğiniz diğer işlemleri 'sessizce' gerçekleştirebilir. Bununla birlikte, ilk oyuncu tamamen güvenlidir ve static_castbundan daha güvenli olma eğilimindedir const_cast. Bunun const_castniyetinizi daha iyi static_castilettiği , ancak eylemlerinizin güvenliğini daha iyi ilettiği bir durum olduğunu düşünüyorum .
David Stone

10

Kısa cevap hayır, güvenli değil.

Uzun cevap, eğer onu kullanacak kadar biliyorsanız, o zaman güvenli olması gerektiğidir.

Oyuncu yayınlarken, aslında söylediğiniz şey, "Derleyicinin bilmediği bir şeyi biliyorum." Const_cast durumunda, söylediğiniz şu: "Bu yöntem const olmayan bir başvuru veya işaretçi alsa da, ilettiğim parametreyi değiştirmeyeceğini biliyorum."

Dolayısıyla, oyuncu kadrosunu kullanırken gerçekten neyi bildiğinizi iddia ettiğinizi biliyorsanız, onu kullanmakta sorun yok.


4

Derleyicinin sabit olduğunu düşündüğü şeyleri değiştirmeye başlarsanız, iş parçacığı güvenliğindeki herhangi bir şansı yok edersiniz.


1
Ne? Değişmez (const) nesneleriniz varsa, bunları iş parçacıkları arasında önemsiz bir şekilde paylaşabilirsiniz. Kodunuzun bir parçası sabitliği ortadan kaldırdığı anda, tüm iş parçacığı güvenliğinizi kaybedersiniz! Neden bunun için modifiye edilmiyorum? iç çekiş
Matt Cruikshank

9
Const kesinlikle kod iş parçacığı güvenli hale getirmede yararlı bir araçtır, ancak hiçbir garanti vermez (derleme zamanı sabitleri hariç). İki örnek: Bir const nesnesinin değişken üyeleri olabilir ve bir nesneye yönelik bir const işaretçisine sahip olmak, nesnenin kendisinin değişip değişemeyeceği hakkında hiçbir şey söylemez.
James Hopkin

Bunun iyi bir cevap olduğunu düşünüyorum çünkü derleyici optimizasyoncunun sizin kelimeyi kullanımınız konusundaki güven ve güvenlik duygularını düşünmedim const. constgüvendir. const_castbu güveni
bozuyor

1
Değiştirilebilir ve iş parçacığı güvenliği ile ilgili olarak: channel9.msdn.com/posts/…
MFH
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.