C++ const_cast nedir anlatabilir misiniz?

turkuazaga

Üye
Katılım
23 Aralık 2018
Mesajlar
58
bir süredir c++ öğrenmeya çalışıyorum baktığım bir programda soyle bir yapı gördüm

Kod:
void find_keyword(const char* buffer, const char* keyword)
{
   char* ncbuf = const_cast<char*>(buffer);
   char* token;
  
    token = strtok(ncbuf, keyword);
    .
    .
    .
}


program çok büyük bu şekilde devam ediyor. Buradaki const_cast olayı nedir?
 
bunun gibi dynamic_cast, reinterpret_casti static_cast gibi başka cast'ler de var. bunların amacı nedir?
 
Bunu daha iyi açıklayabilmek için önce senin yazdığın örnekte fonksiyona giren "const" lu argümanların ne anlama geldiği üzerinde duralım. Eğer bir fonksiyonun pointer argümanlarının başında const varsa, fonksiyon içinde bu pointer üzerinden hazıfada herhangi bir değişiklik yapılamaz. Bunu bizzat derleyicinin kendisi garanti edecektir. Şu örneğe bakalım:

Kod:
#include <stdio.h>

void func1(char* buffer)
{
   buffer[0] = 10;
}

void func2(const char* buffer)
{
   buffer[0] = 10;
}

int main()
{
   char aaa[1000];

   func1(aaa);
   func2(aaa);
}


Bu programda, iki tane fonksiyona bir array adresini veriyoruz. İlk fonksiyon, array adresini char pointer olarak alıyor. İkinci fonksiyon, array adresini const char pointer olarak alıyor. Şimdi derleyelim ve ne olduğunu görelim:

Kod:
[ta@bonsai ~]$ g++ -Wall a.cpp
a.cpp: In function ‘void func2(const char*)’:
a.cpp:10:16: error: assignment of read-only location ‘* buffer’
    buffer[0] = 10;


Görüldüğü üzere, derleyici ilk fonksiyonun array'da değişiklik yapmasına izin veriyor, ama ikinci fonksiyona izin vermiyor ve derleme bir hata mesajı ile sonlanıyor.
 
Yani biz fonksiyon'daki pointer argümanın önüne "const" koyarak, bu fonksiyonu çağıracak olanlara şu sözü veriyoruz: "bu pointer ile hafızada hiçbir değişiklik yapmayacağım, sadece hafızadan okuma yapacağım". Bu da bizzat derleme aşamasında garanti ediliyor. Hatta, verilen pointer'dan yeni bir pointer oluşturup hile yapmaya kalksak bile işimiz olmuyor:

Kod:
#include <stdio.h>

void func1(char* buffer)
{
   buffer[0] = 10;
}

void func2(const char* buffer)
{
   buffer[0] = 10;

   char* xxx = buffer + 47;

   *xxx = 3;
}

int main()
{
   char aaa[1000];

   func1(aaa);
   func2(aaa);
}


Burada, yeni bir xxx pointer tanımlayıp, buffer'in 47 ilerisine işaret ettiriyoruz ve sonra da orasını değiştirmeye kalkıyoruz. Ama derleyici bizi gene de enseliyor:


Kod:
[ta@bonsai ~]$ g++ -Wall a.cpp
a.cpp: In function ‘void func2(const char*)’:
a.cpp:10:16: error: assignment of read-only location ‘* buffer’
    buffer[0] = 10;
                ^~
a.cpp:12:23: error: invalid conversion from ‘const char*’ to ‘char*’ [-fpermissive]
    char* xxx = buffer + 47;
 
Son düzenleme:
Bu const olayı, kaliteli bir C++ programı yazmak için bolca kullanılması gereken birşey. const'u gereken yerlerde kullanarak, derleyicinin sizin yaptığınız hataları yakalamasına yardımcı olursunuz. Eğer bir programın içinde bolca görüyorsanız, baktığınız programın kaliteli bir program olma olasılığı yüksektir.

const_cast ise, bir fonksiyona const olarak gelen bir pointer'i const olmaktan çıkarıyor. Şu örneğe bakalım:

Kod:
#include <stdio.h>

void func(const char* buffer)
{
   char* p = const_cast<char*>(buffer);

   p[0] = 10;
}

int main()
{
   char aaa[1000];

   func(aaa);
}

Bu programı derliyoruz, bir hata yok. Burada olan, func fonksiyonuna const olarak gelen "buffer" argümanından yeni bir pointer oluşturuyoruz, ama bu yeni pointer'i const olmamasını sağlıyoruz. Böylece neticede "buffer" pointer'i ile değişiklik yasak iken, artık değişiklik mümkün hale geliyor! Yani "iyi birşey" dediğimiz const kullanımının tamamen anlamsız hale getiriyoruz. Peki neden? Niye böyle bir özellik konmuş C++ diline?
 
const_cast kullanımının benim bildiğim iki tane geçerli kullanım alanı var:

1) Bazan bir nesnenin effektif değeri değişmiyorken, iç yapısındaki bazı değişkenlerin değerinin değişmesi gerekebilir. Örneğin bir nesnenin adresi, bir const pointer olarak bir fonksiyona giriyor. Bu fonksiyonda, o nesnenin durumunu okuyoruz, ve bu okuma olduğu için sorun yok. Ama nesnenin durumunun kaç kere okunduğunu da nesnenin kendisinin takip etmesini istiyoruz. Bu durumda, her durum okuma yapıldığında nesnenin içindeki bir değişken (durum okuma sayacı) değişecek, ama pointer const, değiştiremiyoruz ... İşte bu tip sorunları çözmek için const_cast kullanabiliriz. Programcı olarak, biz biliyoruz ki, o nesnenin durumu aslında değişmiyor. Biz sadece okuma sayısını takip etmek için bir değişkeni değiştiriyoruz. Belki de bu işi programı debug ederken istiyoruz, ve bir #ifdef ile sadece gerektiğinde bu sayma işini ve const_cast'i devreye sokuyoruz.

2) C'nin ana kütüphanesi olan ve C++ tarafından da kullanılan "C runtime library" de bazı fonksiyonlar vardır, aslında kendilerine verilen buffer'da bir değişiklik yapmadıkları halde, fonksiyonların prototiplerinde bu buffer'lar const olarak işaretli değildir (örnek, writev fonksiyonu). Çünkü bu fonksiyonlar çok eskidir, ve o zamanlar bu const olayının önemi günümüzde olduğu kadar anlaşılmamıştı, o yüzden de kimse fonksiyon prototiplerinde const olayına o kadar önem vermiyordu. Ama günümüzde bu çok önemli, ve biz sırf bu fonksiyon böyle tanımlanmış diye kendi fonksiyonumuzu const'suz bırakmak istemiyoruz. İşte bu durumda, kendi fonksiyonumuzun prototiplerini const olarak tanımlarız, ve fonksiyonun içinde de const_cast ile const'luğunu kaldırıp bu eski, tarihi kütüphane fonksiyonunu çağırırız. Bunun gibi başka özensiz yazılmış kütüphanelerde de, kendisine giren pointer'i sadece okuma için kullanan, ama const olarak işaretlenmemiş fonksiyonlar olabilir. Gidip de bu kütüphanenin kaynak kodunu değiştireceğimize, const_cast ile sorunu çözebiliriz.
 
Son düzenleme:
cevap için tşk ayrıntılı anlatmışsınız ama konunun derin olduğunu görüyorum pek anladığımı söyleyemem
 
Evet, C++ programlarında const'u bol bol ve doğru yerlerde kullanmaya verilen ad "const correctness". Bunun sağladığı faydayı takdir etmen için, "const correctness" a sahip olmayan programlarda bug ayıklarken yıllarca sürünmüş olman lazım :p

Ama burada şunu da belirtmek lazım, örnek olarak verdiğin program, const_cast için uygun ve makul bir kullanım değil. strtok fonksiyonu kendisine verilen string'i gerçekten değiştirir, dolayısıyla find_keyword fonksiyonu kendisini çağıranlara resmen yalan söylüyor. "buffer'i değiştirmem" diyor, sonra da bir güzel değiştiriyor. O yüzden o örneği geçerli bir örnek olarak almamalısın :)

Oradaki örnekte niyet iyi, çağıranın buffer'ini değiştirmeden iş yapmak istiyor. Ama bunu gerçekleştirmek için şöyle birşey yapılabilir:

Kullanıcının verdiği buffer, başka lokal bir buffer'a kopyalanır, sonra da strtok'un bu lokal buffer'da işini yapması sağlanır. const_cast'e de gerek kalmaz, ve fonksiyon da verdiği sözü tutmuş olur.
 
C ve C++ da "cast", bir veri tipini başka bir veri tipi olarak erişmek anlamındadır. Örneğin C'de type cast için aşağıdaki örnekte "char" tipinde bir dizin olan abcd'yi "int" tipinde bir dizin olarak kullanımı var.

Kod:
char abcd[200];

int *ptr = (int*)abcd;

*ptr = 200000;


Bu şekilde parantez kullanarak yapılan cast, C++ da da çalışır, ama tavsiye edilmez. Çünkü bu şekilde yapılan cast'ler kaynak kodu içerisinde göze çarpmıyor. Aratarak bulmak da çok zor, çünkü mümkün olan her cast'i bulabilen bir regexp yok.

C++'da, cast için özel ayrılmış kelimeler var: static_cast, reinterpret_cast, dynamic_cast, ve const_cast. Bunları her editörde kolaylıkla aratıp buldurabiliriz. Sonra da her bir cast meşru mu değil mi inceleyebiliriz.
 
Mesleğe yeni atılan programcıların başını belaya sokan en büyük hatalardan birisi, düşüncesizce type cast kullanmak. Baktınız derleyici sizin programı derlemiyor, tip uyuşmazlığı hatası veriyor, siz de hatayı nasıl gidereceğinizi bilmiyorsunuz, hemen bir type cast yapıp derleyicinin çenesini kapatıyorsunuz. Ama aslında yaptığınız, programa bulunması zor bir bug eklemek ...

Type cast'i sadece mutlaka gerekli olduğu durumlarda kullanmalıyız.
 
Son düzenleme:

Çevrimiçi personel

Forum istatistikleri

Konular
5,653
Mesajlar
97,270
Üyeler
2,438
Son üye
İbrahimSönmez

Son kaynaklar

Son profil mesajları

cemalettin keçeci wrote on HaydarBaris's profile.
barış kardeşim bende bu sene akıllı denizaltı projesine girdim ve sensörleri arastırıyorum tam olarak hangi sensör ve markaları kullandınız yardımcı olabilir misin?
m.white wrote on Altair's profile.
İyi akşamlar.Arabanız ne marka ve sorunu nedir.Ben araba tamircisi değilim ama tamirden anlarım.
* En mühim ve feyizli vazifelerimiz millî eğitim işleridir. Millî eğitim işlerinde mutlaka muzaffer olmak lâzımdır. Bir milletin hakikî kurtuluşu ancak bu suretle olur. (1922)
Kesici/Spindle hızı hesaplamak için SpreadSheet UDF'leri kullanın, hesap makinesi çok eski kalan bir yöntem :)
Dr. Bülent Başaran,
Elektrik ve Elektronik Mühendisi
Yonga Tasarım Özdevinimcisi
Üç güzel "çocuk" babası
Ortahisar/Ürgüp/Konya/Ankara/Pittsburgh/San Francisco/Atlanta/Alaçatı/Taşucu...

Back
Top