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 hede(){
    std::auto_ptr<T> p( new T() );
    p->hodo();
    …
}    // 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.

 
void hede(){
    std::auto_ptr<T> p1( new T() );
    p1->hodo();
    std::auto_ptr<T> p2( p1 ); // su anda artik p1 resetlendi
    p2->hodo();
    std::auto_ptr<T> p3;
    p3 = p2;   // artik p2 de resetlendi
    // sadece p3 nesnemizin sahibi
    p1->hodo()    // !!!!calisma zamani hatasi
    p2->hodo()    // !!!!calisma zamani hatasi
    p3->hodo()    // OK. cunku p3 nesneye bakiyor
}    // p1 ve p2 resetlendigi icin hicbirsey yapmiyor, p3 nesneyi siliyor

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

 
std::auto_ptr<T> Uretici(){
    return std::auto_ptr<T>( new T() );
}

void Tuketici( std::auto_ptr<T> p ){
    p->hodo();
}

void hede(){
    Tuketici( Uretici() );
}

Ü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ızsa 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.

 
class T{
public:
    T() : u( new U() ) {} // u ilkleme listesinde sistemden aliniyor
    ~T(){} // burada delete yapmaya gerek yok cunku nesnenin kapsami bitti

private:
    T( const T&);  // kopyalanamaz
    T& operator=( const T& );   // atanamaz

    std::auto_ptr<U> u;
};

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ında 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 u 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.

Bu noktalara dikkat edilerek kullanıldıklarında auto_ptr’ler özellikle üretici/tüketici ilişkileri olan sınıflar için çok zarif ve güvenli kod yazılmasını sağlarlar.

Share

Comments

Leave a Reply