boost-library

boost::scoped_ptr en basit akıllı işaretçi türü. Yaptığı iş sadece bir tane nesneye işaret etmek ve o nesnenin tek sahibi olup, silinirken de nesneyi de kendisi ile beraber silmek. 

Önce probleme bakalım.

 
void hede(){
    T* t = new T();

    // birseyler yap

    delete t;
}

Bu koddaki problem şu: Eğer fonsiyon ortadaki işlemler esnasında dönerse delete t komutu çalışmayacak ve t nesnesini sızdırmış olacağız. Bahsettiğimiz geri dönüş birkaç şekilde olabilir:

Bu üç durumda da t nesnesini sızdırmış oluruz. Oysa ki bu üç durumda da yığıt(stack) içinde yaşayan bütün yerel nesneler yıkıcıları(destructor) çağrılarak yok edilirler. İşte bu yüzden biz de normal işaretçiler yerine scoped_ptr nesnelerini yığıtta yaratırız:

 
void hede(){
    boost::scoped_ptr<T> p( new T() );

    // birseyler yap

}  // fonksiyon kapsamından çıkılırken p siliniyor
    //ve baktığı nesneyi  de siliyor

Bu şekilde en başta p akıllı işaretçisi yeni T nesnesine bakacak şekilde yaratılıyor ve ilkleniyor(initialization). Ardından fonksiyondan nasıl çıkılırsa çıkılsın, yerel yığıt değişkeni olan p silinirken, yıkıcı metodunun içinde delete çağrılıyor. Böylece fonksiyonda ne olursa olsun T nesnesini sızdırmıyoruz.

Yani akıllı işaretçimiz yaratıldığı kapsam(scope) içinde olunduğu sürece sahip olduğu nesneye işaret ederken, kapsam dışına çıkıldığı anda, kendisi yok olurken, işaret ettiği nesneyi de siliyor. Bu yüzden adı Kapsam İşaretçisi(Scoped Pointer).

scoped_ptr’nin bir diğer önemli özelliği de kopyalanamaması ve atanamaması(assignment). Bunun sebebi scoped_ptr’nin sadece bir objeye sahip olması ve bu sahipliği başka bir scoped_ptr nesnesine devredememesinin özel olarak hedeflenmiş olması.

 
boost::scoped_ptr<T> p1(new T() );
boost::scoped_ptr<T> p2(p1);  // olmaz!!! derleme hatasi verir
boost::scoped_ptr<T> p3;
p3 = p1  // olmaz!!! derleme hatasi verir

Bu kısıtlamanın konulmasındaki amaç, programcının yarattığı nesnenin ömrü ile ilgili daha net kod yazmasını sağlayarak, gelecekte olası problemleri önlemek. Örneğin yukarıdaki hede fonksiyonuna yıllar sonra başka bir programcı ilaveler yapmak durumunda kalırsa, orada yaratılan T objesinin ömrünün, o kapsam içinde sınırlı olması gerektiğini hemen anlayabilir. Böylece mesela yanlışlıkla, o ömrü daha uzun bir başka işaretçiye, p’nin değerini atamaz. Çünkü bunu denerse hemen derleme hatası alır.

Eğer bu kısıt olmasa ve bu atamayı yapabilseydi hata yapmış olacaktı. Mesela düz işaretçiler kullansa, atama yapılan daha uzun ömürlü işaretçi çürük(dangling) bir işaretçi haline gelecekti. Akıllı bir işaretçi kullansa da bu sefer T nesnesini, gerektiğinden uzun süre canlı tutmuş olacaktı.

scoped_ptr’ın kopyalanamaz ve atanamaz olması, kullanımı da çok daha kolaylaştırmış oluyor. Bundan sonra alışkanlık olarak aynı kapsam içinde dinamik olarak yaratıp sildiğiniz bütün nesneler için her zaman scoped_ptr kullanmanızı tavsiye ederim.

Bir uyarı daha. scoped_ptr’ ler kopyalanamaz ve atanamaz oldukları için std::vector, std::list gibi hiçbir STL kabına(container) konulamazlar. Çünkü STL kapları içlerine konulan nesne sınıflarının kopyalanabilir ve atanabilir olmasını gerektirir. Eğer scoped_ptr’leri STL kaplarına koyabilseydik, yine kapsamının dışında o nesneleri yaşatıyor olurduk, ki bu belirttiğim gibi tasarım hedefine ters. STL kapları ile kullanacağımız akıllı işaretçiler boost::shared_ptr ve boost::weak_ptr olacak.

Son olarak scoped_ptr’ler yerel nesneler dışında bir de pimpl(pimpıl diye okunur) yaklaşımında kullanılır. Bu yaklaşımdan şimdi bahsetmeyeceğim.

Share

Comments

Leave a Reply