unique_ptr sınıf şablonu – 2

nesne kaynağı ve boşaltım havuzu

Sahipliğin devredilebilmesi unique_ptr nesnelerine özel bir kullanım alanı sunar: İşlevler dinamik nesnelerin sahipliğini unique_ptr nesneleri ile başka işlevlere aktarabilirler.

Bu iki ayrı yolla olabilir:

1. Bir işlev bir veri boşaltım havuzu (sink) olarak kullanılabilir.

Bu durumda, çağrılan işlevin parametre değişkeni kendisine sağ taraf değeri olarak gönderilen unique_ptr nesnesinin kaynağını devralır.
Böylece, işlev sahipliğini devraldığı nesnenin sahipliğini yeniden bir başka koda devretmez ise işlevin kodunun çalışması sonlandığunda unique_ptr nesnesinin sahiplendiği dinamik nesne silinir:

2.Bir işlev nesne kaynağı olarak davranabilir. unique_ptr geri döndürüldüğünde geri döndürülen sınıf nesnesinin sahipliği işlevi çağıran koda devredilir. Aşağıdaki örnek bu tekniği gösteriyor:

source işlevi her çağrıldığında new işleciyle dinamik bir Myclass nesnesi yaratılmış olur ve source işlevi bu nesneyi sahipliği ile birlikte kendisini çağıran koda gönderir.
İşlevin geri dönüş değerinin p isimli unique_ptr nesnesine atanması dinamik nesnenin mülkiyetini bu nesneye devreder. Döngünün ikinci ve daha sonraki turlarında nesnesine yapılan her atama p‘nin daha önce sahiplendiği dinamik nesneyi siler.

g işlevinin çıkışında p nesneninin ömrü sona erdiğinden p için çağrılan sonlandırıcı işlevin çağrılması p‘nin sahipliğini üstlendiği son dinamik Myclass nesnesinin de delete edilmesini sağlar. Bir kaynak sızıntısı mümkün değildir. İşlev içinden bir hata nesnesi gönderilse dahi, bir unique_ptr nesnesinin sahibi olduğu dinamik nesne silinecektir.

unique_ptr nesnelerinin veri öğesi olarak kullanılması

unique_ptr nesnelerinin sınıfların veri öğeleri yapılmasıyla kaynak sızıntıları engellenebilir. Ham göstericiler yerine akıllı göstericilerin kullanılması durumunda sonlandırıcı işleve gerek kalmaz. Nesnenin ömrünün bitmesiyle, veri elemanı olan akıllı gösterici nesnelerinin de hayatı sonlanacak bu da dinamik nesnelerin delete edilmesini sağlayacaktır. Ayrıca unique_ptr nesnelerinin kullanılmasıyla bir sınıf nesnesinin hayat başlama sürecinde bir hata nesnesini gönderilmesi durumunda kaynak sızıntısı engellenmiş olur. Bir sınıf nesnesi için sonlandırıcı işlevin çağrılabilmesi için söz konusu nesnenin kurucu işlevinin kodu tamamen çalışmış olmalıdır. Kurucu işlev içinden bir hata nesnesi gönderilirse yalnızca kurulumu tamamlanmış veri öğeleri olan sınıf nesneleri için sonlandırıcı işlev çağrılacaktır. Eğer sınıfın birden fazla ham gösterici veri öğesi var ise, birinci new işlemi başarılı olduktan sonra ikincisi başarısız olursa kaynak sızıntısı oluşur.

Örneğin:

Bu tür bir kaynak sızınıtısını önlemek için unique_ptr sınıf nesneleri kullanılabilir:

Artık sonlandırıcı işleve gerek kalmaz çünkü unique_ptr nesnelerinin sonlandırıcı işlevleri  dinamik A nesnelerinin delete edilmesini sağlar.
B sınıfı için kopyalayan kurucu işlevin ve kopyalayan atama işlevinin de yazılması gerekir. Çünkü öğe olarak kullanılan unique_ptr nesneleri derleyicini yazacağı kodla kopyalanamaz. Eğer bu işlevler tanımlanamaz ise B sınıfı türünden nesneler kopyalanamaz yalnızca taşınabilir.

unique_ptr ve diziler

Bir unique_ptr nesnesi aşağıdaki durumlarda sahip olduğu nesneyi delete eder:
unique_ptr nesnesinin hayatı sona erdiğinde
unique_ptr nesnesine yeni bir unique_ptr değeri atandığında
unique_ptr nesnesine nullptr değeri atandığında
unique_ptr nesnesi için sınıfın reset işlevi çağrıldığında

Bu durumlarda silme işlemi delete işleci ile yapılmaktadır.
Ne yazık ki C dilinden gelen kurallar nedeniyle bir göstericinin tek bir nesneyi mi yoksa bir diziyi mi gösterdiği bilinemez. Ancak dinamik dizilerin silinmesi delete işleci ile değil delete[] işleci ile yapılmalıdır. Dinamik bir dizinin delete işleci ile sonlandırılması çalışma zamanı hatasıdır. Aşağıdaki kod geçerli olsa da çalışma zamanı hatasına neden olur:

shared_ptr sınıfı için diziler için silme işlemini gerçekleştirecek özel bir deleter türünün kullanılması zorunludur. İstersek unique_ptr sınıfı için de bu araçla bir deleter oluşturabiliriz. Ama buna gerek yoktur.
C++ standard kütüphanesi unique_ptr sınıfını dizi türleri için özelleştirmiştir . Dizi türleri için yapılan özelleştirme sahiplik sona erdiğinde delete işleci yerine delete[] işlecini kullanır.
Eğer bir unique_ptr nesnesi dinamik bir diziyi gösterecekse bildirim aşağıdaki gibi yapılmalıdır:

Ancak bu özelleştirmede sunulan arayüz birincil şablondakinden  farklıdır.  operator* ve operator*> işlevleri yerine operator[] işlevi sunulmuştır.

Köşeli parantez işlevine gönderilen indisin geçerli bir değerde olmasından programcı sorumludur. Geçersiz bir indis değeri çalışma zamanı hatasına neden olur.
Bu özelleştirilmiş sınıf taban sınıf türünden bir akıllı  göstericinin türemiş sınıf türünden bir diziyle başlatılmasına da izin vermez. Yani çalışma zamanı çokbiçimliliği dizilerde unique_ptr sınıfı yoluyla desteklenmemektedir.

default_delete sınıfı

unique_ptr sınıf şablonunun (basitleştirilmiş) tanımı aşağıdaki gibidir:

Yukarıdaki kodda unique_ptr sınıfının diziler için özelleştirilmesi görülüyor. Tanımdan da görüldüğü gibi özelleştirilmiş sınıfın arayüzünde operator* işlevi ve operator-> işlevi yer almamakta fakat operator[] işlevi bulunmaktadır. unique_ptr sınıfının standart kütüphanede bulunan gerçekleştirimi operator* ve operator-> işlevlerini geri dönüş değerleri türlerinin tam olarak elde edilebilmesi için bazı şablon hileleri kullandığından biraz daha karmaşıktır.
Özelleştirilmiş sınıf için kullanılacak std::default_delete<> sınıfı silme işlemini delete yerine delete[] ile yapar:

Varsayılan şablon tür argumanları otomatik olarak özelleştirmelere de uygulanmaktadır.
Bu yazı Nicolai M. Jossutis‘in The C++ Standard Library isimli kitabının unique_ptr isimli bölümünün serbest çevirisidir.

Necati Ergin

C ve Sistem Programcıları Derneğinde eğitmen olarak çalışıyor.

Bunlar da ilginizi çekebilir

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Kod Eklemek İçin Okuyun