constructor tracker (kurucu işlev izleyicisi)

Aşağıdaki gibi bir sınıf yapımız olsun:

Myclass isimli sınıfın A, B ve C sınıfı türünden veri öğeleri (data members) var. A, B ve C sınıflarının int parametreli kurucu işlevlerinden aynı türden bir hata nesnesi (exception) gönderilmesi olasılığı bulunuyor. Bu ortak hata sınıfının örneğimizde std::runtime_error sınıfı olduğunu düşünelim. Myclass sınıfı için yazacağımız kurucu işlevde, m_a, m_b ve m_c isimli veri öğelerine, işlev öğe ilk değer verme listesiyle (member initializer list) ilk değer vereceğiz. Eğer Myclass sınıfının kurucu işlevi çağrıldığında öğelerden herhangi birinin kurucu işlevinden bir hata nesnesi gönderilirse bu hata nesnesini mutlaka yakalamamız gerekiyor. Ancak belirli bir nedenden, hata nesnesinin hangi öğenin kurucu işlevinden gönderildiğini kesin olarak bilmemiz gerekiyor. Hata nesnesi A. B, C sınıflarının hangisinin kurucu işlevinden gönderildi? Eğer A, B, ve C sınıflarının kurucu işlevleri farklı türlerden hata nesneleri gönderiyor olsaydı uygun bir catch blokları sıralamasıyla istediğimiz bilgiyi elde edebilirdik. Ancak üç sınıf da aynı türden hata nesnesi gönderiyor. İşimiz zor görünüyor değil mi? Bu bilgiyi elde edebilmek için constructor tracker idiyomunu kullanabiliriz:

Kodu tam olarak anlayabilmemiz için dilimizin bazı araçlarını hatırlamamız gerekiyor:

Myclass sınıfının private bölümünde TrackerType isimli bir içsel enum tür tanımlandığını görüyorsunuz.
Myclass sınıfının kurucu işlevinin TrackerType türünden bir parametre değişkeni var. Bu parametre değişkeninin tek varlık nedeni, hata nesnesinin hangi öğenin kurucu işlevinden gönderildiğinin anlaşılmasında seçici (selector) olarak görev yapacak olması. Bu parametre değişkeni varsayılan arguman olarak TrackerType::NONE değerini alıyor. Bu değer hiçbir öğeden hata gönderilmediğine işaret ediyor.
Myclass sınıfının kurucu işlevi için bir işlev try bloğu (function try block) oluşturulmuş. Bir sınıfın veri öğeleri olan sınıf nesnelerinin kurucu işlevlerinden gönderilen hata nesnelerini yakalamanın tek yolu işlev try bloğu. Bu konuda yeterli bilgiye sahip değilseniz işlev try bloklarını anlatan yazımızı okuyabilirsiniz.

Şimdi de Myclass sınıfı için oluşturulan öğe ilk değer verme listesine göz atalım:

Myclass sınıfının veri öğelerine ilk değer verirken C++11 ile gelen tek biçimli ilk değer verici (uniform initializer) özelliğini kullandık.
m_a, m_b ve m_c öğelerine ilk değer veren ifadeler içinde virgül işleci kullanıldı. Burada virgül atomunun, virgüllerle ayrılmış listenin (comma separated list) virgülü değil de işleç virgül olabilmesi için ilk değer verici ifadenin bir parantez içinde alınması gerekiyor.
Virgül işlecinin C dilinden gelen iki önemli özelliğini anımsayalım:
Virgül işleci bir yan etki noktası (sequence point) oluşturur. Yani virgül işlecinin sol teriminin sağ teriminden önce yapılması garanti altındadır.
Virgül işlecinin ürettiği değer sağ teriminin değeridir:

gibi bir ifade olsun. expr1 ifadesinin expr2 ifadesinden önce yapılması garanti altındadır.
Bu ifadenin değeri expr2 ifadesinin değeridir.
Hatırlamamız gereken önemli bir kural da öğelerin hayata gelme sırasına ilişkin. Bir sınıfın statik olmayan veri öğelerinin hayata gelme sırasını belirleyen bu veri öğelerinin sınıf içindeki bildirim sırası.

Bir işlevin çağrılmasından önce işleve gönderilen arguman olan ifadelerin oluşturacağı yan etkiler tamamlanmak zorunda.

ifadesinde önce atama yapılacak daha sonra işleve ifadenin değeri olan 0 değeri gönderilecek. Eğer m_a için çağılan kurucu işlev hata nesnesi gönderirse, programın akışı hatayı yakalayan catch bloğuna çekileceğinden tracker isimli parametre değişkeni ONE değerinde kalacak. İlk değer verme listesinden hata nesnesinin gönderilmesi durumunda işlev try bloğuna ilişkin catch bloğu hatayı yakalayacak. Hata nesnesinin hangi kurucu işlevden gönderildiğini tracker değişkeninin değerinden anlayacağız.
İşlev try bloğunu izleyen catch bloğu içinde işlevin parametre değişkenleri görülür (visible) durumdadır. Eğer catch bloğu içinde parametre değişkeni olan isim görünür olmasaydı kod sentaks hatası olacaktı.

Bu idiyom A, B ve C sınıflarının kurucu işlevlerinin en az bir parametreye sahip olmasına dayanmaktadır. Eğer bu sınıfların varsayılan kurucu işlevleri (default ctor) söz konusu olsaydı o zaman bir uyumlandırıcı sınıf kullanmamız gerekecekti.

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