15 Haziran 2017 Perşembe

C++ Akıllı İşaretçiler (Smart Pointers)


Smart pointer C++ standart kütüphanesinde #include <memory> header dosyasında tanımlıdır ve amacı kaynak yönetiminin otomatik gerçekleştirilmesini sağlamaktır. Pointer 'lar hafızada belirli bir alanın adresini gösterir ve bu alanda verinin tutulması için hafızada yer açma ve ilgili veri ile işlem bittiğinde bu verinin silinmesi sorumluluğu programcıya aittir. Smart pointer larda ise hafızanın boşaltılması işlemi otomatik olarak uygun bir zamanda gerçekleştirilir.Uygun zaman biraz ucu açık bir kavram tabi ki, isterseniz şimdi bir örnek üzerinden normal (raw) pointer ile smart pointer farkını, hafızanın nasıl otomatik silindiğine dair bir örnek üzerinden görelim;





Her iki fonksiyonda da fonksiyon içerisinde bir pointer tanımlanıp, pointer ın işaret ettiği alana değer ataması yapılıyor. Daha sonra ise fonksiyon içerisindeki yerel değişkenlerin adresi global değişkenlerin adresine atanıyor. Ekran çıktısında göreceğiniz gibi raw pointer ın atandığı global *y değeri ile *x aynı değere sahip. Çünkü x ve y değişkenleri aynı hafıza adresini gösteriyor. Fakat main içerisindeki smart pointer global *sy nin değeri ise ekrana boş olarak yazdırılıyor. sy.reset(sx.get()); kod parçacığı ile sx pointer ı resetlendi, yani artık saklanan nesnenin yeni sahibi sy oldu!. unique_ptr kullandığımız için sy = sx ataması yapamıyoruz yani iki ayrı pointer ın aynı hafıza adresini göstermesini sağlayamıyoruz! UseSmartPointer içerisindeki (smart x :)) sx isimli akıllı pointer ımız tanımlandığı fonksiyonun kapsamının dışına çıkınca sx in işaret ettiği yerdeki değer otomatik olarak siliniyor. (Not: sy nin değerini boş yazacak dedik ama aslında sy pointer ı da silindi ve ona erişemiyoruz, çünkü sx ile aynıydı :) yani kod aslında hata verecek ama amacımız zaten otomatik silinmeyi göstermek idi)   İlk paragrafta bahsettiğimiz uygun bir zaman kavramına geri dönecek olursak; uygun zaman bu örnek için kapsama alanının dışına çıkılması anlamına geliyor. Özetle; smart pointer da tutulan veriler, kapsama alanının dışına çıkılınca otomatik olarak siliniyor!!!


Yukarıda verdiğimiz örnekte UseRawPointer fonksiyonundaki x pointer ını silmedik bu nedenle hafızada yer kaplamaya devam ediyor olacak. Ayrıca bu örnekte unique_ptr kullandık, unique_ptr şu anlama geliyor: aynı kaynağı işaret eden en fazla bir pointer olabilir. Şimdi vereceğim örnekte ise shared_ptr kullanacağız. shared_ptr ile birden fazla pointer aynı kaynağa işaret edebilir..





Ekran çıktısına baktığımızda raw pointer ile aynı davrandı. sx pointer ı kapsama alanı dışında kaldığı için otomatik olarak silindi, Fakat sy hala verinin saklandığı yeri gösteriyor. Buradaki avantaj akıllı pointer sx i silmek ile uğraşmadık, boş yere de yer kaplamamış oldu.

shared_ptr kullanarak ilgili kaynağı kaç farklı pointer ın işaret ettiğini de öğrenebiliriz (reference counting). Örneğin aşağıdaki örnekte 2 pointer aynı değeri işaret ediyor, ve bu pointer lardan birisini silince use_count değeri bir azalıyor.



Bir başka akıllı pointer tipi ise weak_ptr 'dir. weak_ptr shared_ptr ile yönetilen bir nesneye referans olan bir akıllı pointer dır. C++ ta bir pointer ın sahipliği kavramı, pointer ın sakladığı veriyi kimin silme sorumluluğu taşıdığı ile alakalıdır. weak_ptr işaret edilen nesne üzerinde geçici bir sahiplik sağlar, yani işaret ettiği hafızadaki nesne aynı(değişmeden) kaldığı müddetçe ilgili hafıza adresini saklar. Fakat weak_ptr nin işaret ettiği yerdeki değer değişirse weak_ptr (adı üstünde zayıf) nin bağlantısı da kopar. Bu sebeple de weak_ptr deki verinin geçerliliği expired() ya da lock() metodları ile kontrol edilmelidir. Bu senaryoya ilişkin örnek ve ekran çıktısı aşağıdaki gibidir.








1 yorum: