Plazma sayı 8, sayfa 37

Bu sayfadaki yazılar

Sayfanın metni

Sayfa 37

boost::scoped ptr<T> pl(new T() ); boost::scoped ptr<T> p2(pl); // olmaz!!! boost::scoped ptr<T> p3; p3 pl // 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.

Auto ptr

std::auto ptr, geçen yazıda bahsettiğimiz boost::scoped ptr'den bir adım daha yetenekli bir akıllı işaretçidir. Tıpkı scoped ptr gibi auto ptr de bir nesnenin sahibidir ve kapsam dışına çıkılırken o nesnenin silinmesini sağlar.

void hedel) (| std::auto ptr<T> p( new T() p->hodo();

Vi

// kapsamdan cikilirken T nesnesi silinir

)

Yine bu fonksiyonda ne olursa olsun (erken bir return ya da istisna) auto ptr sayesinde temel istisna güvenliği (yani istisnalar tetiklendiği takdirde bellek sızdırmama garantisi) sağlanmış olur.

Ancak scoped ptr'den farklı olarak auto ptr, kopyalanabilir ve atanabilir. Kopyalama/atama durumlarında nesnenin sahipliği el değiştirir. Başka bir deyişle bir nesneye herhangi bir anda yalnız bir auto ptr sahip olabilir. Bir auto ptr bu şekilde sahiplik kaybettiğinde resetlenmiş olur.

derleme

std::auto ptr<T> pl( new T() pl->hodo(); std:tauto ptr<T> p2l pl ); p2->hodo(); ptr<T> p3; p3 p2; // artik p2 de resetlendi // sadece p3 nesnemizin sahibi

Vi

// su anda artik pl resetlendi

pl->hodo() // zamani hatasi p2->hodo () // 1!!!calisma zamani hatasi p3->hodo() // OK. cunku p3 nesneye bakiyor

) // pl ve p2 resetlendigi icin hicbirsey yapmiyor, p3 nesne

Dolayısıyla auto ptr'ler sahip oldukları nesneyi kopyalama/atama yoluyla birbirlerine devredebilirler. Bu sebeple bazı durumlarda fonksiyonlara argüman olarak geçirilmeye veya fonksiyonlardan geri döndürülmeye çok müsaittirler.

std::auto ptr<T> Üretici()( return std::auto ptr<T>( new T()

Vi ) void Tuketici( std::auto ptr<T> p )( p->hodo();

) void Tuketici(

Vi

Üretici ve Tüketici metodlar karşımıza çok sık çıkarlar. Örneğin birbirine mesaj gönderen veya iş atayan sınıflar mesaj nesneleri üretip tüketiyor olabilirler. Normalde bu yapıda nesnelerin üretilip, el değiştirip, tüketilip, silinmeleri pek çok potansiyel bug/sızıntı noktası taşır. Eğer düz işaretçiler kullanılırsa, nesnelerin sahibinin kim olduğu, hangi işaretçilerin ne zaman sıfırlanacağı gibi konular problem yaratabileceği gibi, herhangi bir basamakta olacak bir istisna tetiklemesi de sızıntıya sebep olur. auto ptr kullanmak bu sorunların hepsini çok zarif bir şekilde çözer. Buna benzer bir problemle bir sonraki karşılaşmanızda auto ptr kullanmak aklınızda olsun.

Son olarak, gerek scoped ptr, gerekse auto ptr, sınıflarda üye değişken olarak da kullanılabilir. Böyle kullanıldıklarında sınıfın yıkıcı metodu içinde delete çağrılmasına gerek kalmamış olur.

elass Tİ public: T() : u( new Ul) ) () // u ilkleme listesinde sistemden ali // burada delete yapmaya gerek yok cunku nesnenin ke private: T( const T&); // kopyalanamaz T& operator-( const T& ); // atanamaz std:tauto ptr<U> ü; VW»,

Burada dikkat etmeniz gereken şey, kopya yapıcı ve atama operatörünün private yapılarak, sınıfın kopyalanamaz ve atanamaz hale getirilmesi. Nitekim sınıfın kopyalanmasına izin verseydik, bu sınıftan bir nesneyi başka bir nesneye kopyaladığımız anda, nesnelerden biri sahip olduğu nesneyi kaybedecekti. Çünkü bir nesnenin auto ptr'si diğer nesneninkine kopyalanacak ve sadece bir auto ptr nesneye bakmaya devam edecekti.

Aynı sebepten ötürü auto ptr de tıpkı scoped ptr gibi STL kaplarında kullanılmaya uygun değildir. Kopyalanabilir olduğu halde, auto ptr kopyaları birbirine denk olmadıkları için, STL kaplarının metodları kendi içlerinde kopyalamalar yaparken auto ptr'leri istemeden resetlemiş olurlar. Mesela içi auto ptr'lerle dolu bir std::vector kabına std::sort işlemini uyguladığınızı düşünün.

Klavyeyle gezinmek için ← ve → tuşları.