+ Cevap Yaz
Toplam 6 sayfadan 4. sayfa
İlkİlk 1 2 3 4 5 6 En SonEn Son
57 sonuçtan 31 ile 40 arası gösteriliyor

Konu: dev c++'ı nasıl bilirsiniz?

  1. #31
    Ali Çehreli
    Üyelik Tarihi
    10/2002
    Mesaj
    2,900

    Alıntı _Onk@_, mesajından alıntı: Mesajı Gör
    1. İleri C++ konuları özellikle Hata Yakalama ve İşleme ile ilgili kaynak olarak neyi tavsiye edersiniz. Baskılı, internet...
    Benim bu konuda gözümü açan, Herb Sutter'ın Exceptional C++ kitabı olmuştu. İngilizce kaynak yetenler için GoW de olur.

    2. catch ile hatayı yakaladığımızda yapacağımız işlemler ne olmalıdır?
    O soruyu ortadan kaldıracak bir ilke: hatayı, ancak ve ancak ne yapacağını bildiğin düzeyde yakala. (Bu arada, daha önce "öğüt" dediklerimin de doğrusu herhalde "ilke"ydi. "Guideline"ın Türkçesi olarak kullanıyorum.)

    Örneğin zarf_hazirla() işlevi, adres bilgisini bulamadığı için işini yapamadığı için hata atıyor.

    Bu hata, onu çağıran bir üst işlev tarafından yakalanabilir: faturayi_gonder(). Belki bu işlev, bir hata atıldığında faturayı gönderme işini tekrar sıraya koyuyordur. Yani, bu hatayı kendisi yakalarsa, faturayi_gonder() işlevini çağıranın bu hatadan haberi olmaz, daha üst işlev bir sonraki müşteriye geçer ve onun için faturayi_gonder()'i çağırabilir.

    Başka bir tasarımda, faturayi_gonder() işlevi hatayı kendisi yakalamaz. Çünkü örneğin faturayı gönderemediğinde işlemi tekrar sıraya koyacak şekilde programlanmamıştır. O zaman hatayı kendisi yakalamaz ve hata üst işleve gider. Belki de üst işlev butun_musterilerin_islemlerini_yap() işlevidir. Belki de hatayı o yakalar ve ne yapıyorsa yapar. En azından bir hata mesajı yazar ve program belki de tekrar ana menüye geçer.

    Kısacası, catch zaten hata yakalandığında ne yapılacağının bilindiği düzeyde yakalanır. Bu da C olması gerektiği gibi hatanın elden ele iletildiği tasarımlardan iki nedenle üstündür:

    - programın asıl kodları hata ile ilgilenmezler; herkes kendi işini yapar; hata atılmışsa atılmıştır

    - hatanın iletilmesinin unutulması diye bir sorun yoktur; atan atar, yakalayan yakalamazsa program sonlanır; çok önemli: program yanlış verilerle işine devam etmemiş olur

    Tabii bütün bunları program hata atıldığında da doğru çalışacak şekilde yazıldığı durumlar için söylüyorum. Yani programın "exception-safe" yazıldığı durum için.

    3. Tüm exceptions'ların listesini nerden bulabilirim ya da hangi işlevin hangi exception'u fırlatacağını nereden öğrenebilirim.
    Çağrılan işlev attığı hatayı da belgelerinde bildirir. Ama yine de o hataları her çağıran ortamda yakalamak zorunda değilizdir.

    Kullanıcı hatalarının std::runtime_error'dan türetilmeleri önerilir. O da std::exception'dan türemiş olduğu için, "ne hata olursa olsun" yakalamak isteyen bir düzey, "std::exception"ı yakalar ve her hatayı yakalamış olur.

    Takip ettiğim/etmeyi düşündüğüm kaynaklar:
    MSDN http://msdn.microsoft.com/en-us/libr...8VS.80%29.aspx
    C++ Reference http://www.cppreference.com/wiki/exception/start
    CPP.com http://www.cplusplus.com/doc/tutorial/exceptions/
    GotW
    Sefer ALGAN'ın makalesi: http://www.csharpnedir.com/articles/...%20Yakalama%29
    Kaan ASLAN : İleri CPP notları
    Ben yalnızca GoW'da deneyimliyim ve öneririm. Diğerlerinden iyi bulduklarını da sonra sen önerirsin.

    Ali

  2. #32
    Ali Çehreli
    Üyelik Tarihi
    10/2002
    Mesaj
    2,900

    Alıntı e_koca, mesajından alıntı: Mesajı Gör
    Ne demek istediginizi anlamadim, biraz daha acarmisiniz?
    O ilkeleri çok hızlı bir şekilde yazmıştım... Tabii ki açıklamak gerek...

    Bir sınıfın üye işlevi içindeyiz diyelim. Bu nesnenin üyelerinde değişiklik yapmamız gerekiyor... İlkenin söylediği şu: önce hata atma olasılığı olan işlemleri yap, ancak onlar başarılı olur da hata atılmazsa nesnenin üyelerini değiştir.

    Bunun en güzel örneği atama işlecidir. Atama işleci iki işlemden oluşur: eldeki kaynakları geri veri, yeni kaynakları kopyala. Ve yanlış olarak şöyle yazılabilir:

    Kod:
    Foo & Foo::operator= (const Foo & sagdaki)
    {
        if (this != &sagdaki) {
            kaynaklari_geri_ver();           // <-- YANLIS
            kaynaklari_kopyala(sagdaki);
        }
    
        return *this;
    }
    
    Bunun nedeni, kaynakların sağdaki nesneden kopyalanması sırasında hata atılabileceği, ve bu yüzden bu nesnenin artık kaynaksız ve tutarsız bir durumda kalabileceğidir.

    Atama işleci, bu ilkenin söylediği gibi yazılırsa, atama işleminin iki adımının ters sırada yapılmaları gerekir: önce kopyala, sonra kaynakları geri ver:

    Kod:
    Foo & Foo::operator= (const Foo & sagdaki)
    {
        Foo gecici(sagdaki);         // <-- kopyala
    
        // hata atmayan 'swap' islemi:
        this->degis_tokus_et(gecici);
    
        return *this;
    
    } // <-- eski kaynaklar bu noktada, gecici sonlandirilirken geri verilir
    
    Burda hatayi yakalamaktanmi, yoksa islemektenmi bahsettiniz ?
    "hataları hiçbir zaman sonraya bırakma; sınıfları tasarlarken de akılda olsun" ilkesi, zaten yazılmış bir programın hatalar karşısında doğru çalışacak şekilde düzeltilmesinin zor olacağını söyler. Hatalar (exception), tasarımın başından akılda tutulması gereken bir düzenektir.

    Bunun bir örneği, veri yapılarından 'stack'tir. Bu veri yapısının klasik arayüzünde iki işlev bulunur:

    - push: topluluğa yeni eleman ekler
    - pop: topluluğun tepesindeki çıkartır ve bize döndürür

    O arayüz hatalara uygun değildir. Çünkü pop'un, çıkarttığı elemanı *kopyalayarak* döndürmesi gerekir. (Bunun örnek bir kodu yukarıda bağlantısını verdiğim sunuda var)

    Eğer o kopyalama işlemi hata atarsa, veri yapısından bir eleman eksilmiş, ama hiç kimse o elemanı görememiş olur.

    'stack'in hatalara uygun arayüzünde üç üye olması gerekir:

    - push: topluluğa yeni eleman ekler
    - top: topluluğun tepesindekine erişim sağlar
    - pop: topluluğun tepesindekini çıkartır

    Görevlerin böyle bölünmüş olmaları, bu veri yapısını hatalar karşısında doğru çalışmasını sağlar. (Daha önce "cohesion" sözcüğünü yanlış yerde kullandım; "cohesion" bu kavrama uygundur.)

    Mesela siralama islemi yapan bir isleve, tamam sen siralamani yap ayni zamanda en buyuk sayiyida bize dondur dedigimiz zaman.
    Belki daha iyisi, sıralama ile en büyüğe erişimi birbirlerinden ayırmaktır.

    Aslında en büyüğüne erişim sağlama işleminde hata atacak bir şey yoksa, belki o da çalışır. Örneğin dönüş türü bir referans ise, bir sorun yoktur. 'stack'te ise referans olamaz, çünkü veri yapısından çıkartılmıştır. Orada kopyalanması şarttır.

    Mantikli bir ornek degil ama ogrenmek acisindan soruyorum, hata yakalama acisindan bunun sakicasi ne ? Siralamayi yapamadigin icinmi bir hata nesnesi firlatildi yoksa en buyugunu donduremedigi icinmi bir hata nesnesi firlatildi ikileminde biraktigi icinmi ?
    Hayır, o ikilemden bahsetmiyordum. Çünkü atılan hatalar farklı türlerden olabilirler. İşlev duruma göre farklı hata atar, yakalayanlar da özellikle onlardan birisini yakalayabilirler. Veya, _Onk@_'ya yazdığım gibi, her hatayı yakalamak için sıradüzenin en tepesindeki std::exception hatasını yakalarlar.

    Ali

  3. #33
    Ali Çehreli
    Üyelik Tarihi
    10/2002
    Mesaj
    2,900

    Alıntı e_koca, mesajından alıntı: Mesajı Gör
    Bu yuzden smart pointer kullanilmalidir. Diye not almisim zamaninda...
    Evet, daha temiz başka yolu yok.

    Ama smart pointer yerine daha genel de düşünebiliriz: Her kaynak, ancak ondan sorumlu olan bir türün sonlandırıcı işlevinde geri verilmelidir.

    RAII ilkesi gereği, eğer kod içinde açıkça örneğin 'delete' yazmışsak programımız hatalara karşı güvensiz demek olabilir ("exception-safe" değil.)

    Ali

  4. #34
    Üye
    Üyelik Tarihi
    02/2010
    Mesaj
    11

    Kod:
    Foo & Foo::operator= (const Foo & sagdaki)
    {
        Foo gecici(sagdaki);         // <-- kopyala
    
        // hata atmayan 'swap' islemi  //??? 
        this->degis_tokus_et(gecici);
    
        return *this;
    }
    
    Demek istediginizi anladim ama exception-safe`in bu ilkesini aciklarken kafama yerlestirtirdigim atama operator fonksiyonunu`da yiktiniz. Bana bu sekilde ogretilmisti. Biraz hayal kirikligi

    Hatalari hicbirzaman sonraya birakama, bu sinifi tasarlarkende aklinda olsun ilkesinde, yakalamaktanmi yoksa islemektenmi bahsediyosunuz sorusunu sorarken farkli bisey sormak istedim aslinda ama onuda _Onk@_ ya verdiginiz zarf_gonder orneginden aldim. Hatanin ne zaman yakalanip ne kadarinin ne zaman islenecegi tamamen bizim tasarimimiza ve ne gerektirdigine bagli.

    Hatalari hicbirzaman sonraya birakma, sinifi tasarkende aklinda olsun ilkesi anladigim kadariyla, sinif mimarinden baslayarak, kullanici olarak yazdigimiz kodlara kadar exception-safe`i gozet. Gerekirse sinif mimarisini bile buna gore ayarla.

    Bu siralama ve en buyuk islemlerini ornek olsun diye sordum siz direk o ornek uzerinden cevap vermissiniz ama pek tutarli degil. Zamaniniz varsa benim verdigim ornegi unutup bir isleve birden fazla gorev verme ilkesinede bir ornek verirmisiniz ?

  5. #35
    Ali Çehreli
    Üyelik Tarihi
    10/2002
    Mesaj
    2,900

    Önce bir hatırlatma: hata atma konusunda üç güvence olabilir:

    - temel güvence (basic guarantee): hata atılırsa kaynak sızıntısı yok ve nesneler kullanılabilir durumdalar (ama örneğin 'stack' veri yapısından eleman kaybedilmiş olabilir)

    - sağlam güvence (strong guarantee): hata atılırsa programın durumunda hiçbir değişiklik yok

    - atmama güvencesi: bu işlevden hata çıkmaz (kendisi atmaz ve atılanları yutar; 'swap' böyle bir işlev olmak zorundadır)

    Şimdi elimizde şöyle bir işlev olsun:

    Kod:
    void foo()
    {
        birinci_adim();
        ikinci_adim();
    }
    
    foo sırasında hata atılsa, programın durumu hangi adımda hata atıldığına bağlı olacaktır.

    - Eğer her iki adım da atmama güvencesi veriyorlarsa, yani kendileri hata atmıyorlarsa zaten sorun yok.

    - Eğer adımlar geri alınabilen türden iseler, o işlev sağlam güvence verebilir.

    - Değilse, şimdiye kadar konuştuğumuz ilkeleri uygulayan bir program temel güvence verebilir.

    Sağlam güvence verebilmek için "ya hep ya hiç" mantığıyla çalışan 'transactional' teknolojiler kullanmak gerekir. Örneğin o iki adım bir 'transactional database' ile ilgiliyse, sorun değildir. (Transactional olarak çalışan programlama dilleri olduğunu duyuyorum. (C++ öyle değil.))

    Eğer birinci adımı geri alma olasılığı varsa, benim daha önce kullandığım şöyle bir yöntem kullanılabilir:

    Kod:
    void birinci_adim()
    {}
    
    void ikinci_adim()
    {}
    
    void birinci_adimi_geri_al()
    {}
    
    class BirinciAdimiGeriAlici
    {
        bool gerek_var_;
    
    public:
    
        BirinciAdimiGeriAlici()
            :
            gerek_var_(true)
        {}
    
        ~BirinciAdimiGeriAlici()
        {
            if (gerek_var_) {
                birinci_adimi_geri_al();
            }
        }
    
        void gerek_kalmadi()
        {
            gerek_var_ = false;
        }
    };
    
    
    
    void foo()
    {
        BirinciAdimiGeriAlici geriAlici;
    
        birinci_adim();
        geriAlici.gerek_kalmadi();
        ikinci_adim();
    }
    
    Ama bunlar hep 'sağlam güvence' için. Yoksa, eğer yukarıdaki beş ilkeyi uyguladıysak zaten temel güvenceyi elde etmişizdir...

    Sonuçta; durumlar pek iyi değil... Zaten bu sorunlar çözülebilmiş olsa, herkes hâlâ daha sağlam teknolojiler arayışında olmazdı.

    Ali

  6. #36
    Üye
    Üyelik Tarihi
    10/2006
    Yer
    İstanbul
    Mesaj
    592

    Alıntı acehreli, mesajından alıntı: Mesajı Gör
    C++'da, her sınıf en fazla 1 adet kaynaktan sorumlu olmalıdır.

    Ali
    Yani ben bir matris sinifi yazmak istesem boyle yazmamam mi gerekiyor
    Kod:
    class Matrix {
        int ** elements;
       // ....
    }
    
    Cunku birden fazla kaynagi bunyesinde bulunduruyor.

  7. #37
    Ali Çehreli
    Üyelik Tarihi
    10/2002
    Mesaj
    2,900

    Kare matris ise zaten tek bir bellek ile halledebiliriz. Tam olarak nasıl ayırmayı düşünüyorsun?

    Eğer satırlar ayrı ayrı elde ediliyorsa, bir yöntem:

    Kod:
    boost::ptr_vector<int*> satirlar;
    
    ptr_vector, std::vector'ün aksine, içindeki elemanlara sahip bir yapıdır. Çok basit bir tür aslında, elle de yazılabilir.

    Böylece Matris sınıfı kaynak işleriyle değil, kendi işleriyle ilgilenmiş olur. Kaynaklar ptr_vector'ün sorumluluğunda.

    Tabii ki başka yöntemler de düşünülebilir...

    Ali

  8. #38
    Üye
    Üyelik Tarihi
    10/2006
    Yer
    İstanbul
    Mesaj
    592

    Sorun matris sinifi yazmak degilde, hicbir zaman iki boyutlu pointer tanimlamamam mi gerekiyor? Zira;
    Kod:
    #define ROWS 10
    #define COLUMNS
    int **  Lut_matrix = NULL;
    Lut_matrix = new int *[ROWS];
    
    for(int ii = 0; ii < ROWS; ii++)
        Lut_matrix[ii] = new int[COLUMNS];
    
    Herbiri birer kaynak.

  9. #39
    Ziraat Mühendisi _Onk@_ Adlı Üyenin Profil Grafiği
    Üyelik Tarihi
    09/2008
    Yer
    Ankara
    Mesaj
    711

    Kod:
    #define ROWS 10
    #define COLUMNS
    int **  Lut_matrix = NULL;
    Lut_matrix = new int *[ROWS];
    
    for(int ii = 0; ii < ROWS; ii++)
        Lut_matrix[ii] = new int[COLUMNS];
    
    Yaklaşık iki gündür araştırma yapıyorum. Tavsiye olunan gidiş yolu ise:
    - İstisna fırlatma ihtimali olan kod bölümü try-catch içine alınmalıdır.
    - İstisna fırlatıldıktan sonra istisnayı fırlatan kod parçasının ayırdığı kaynak ile ilgili geri vermek haricinde işlem yapılmamalıdır.

    Nıot: Aşağıdaki metin bölümü hiçbir şekilde doğrulanmamıştır.
    Sizin kodunuzda istisna fırlatma ihtimali olan new işleci, hemde 11 defa işletilmekte. İlk işlemesinde istisna fırlatılırsa Lut_matrix NULL kalır. Ondan sonra hiçbir yeri göstermeyen bir işaretçinin konumuna göre 10 defa da new işletilmeye çalışılır. Aklıma gelen tek çözüm yolu new işlecinin istisna fırlatmasını engellemek ve işaretçinin üzerinde kontrol yapmaktır.

  10. #40
    c3r
    c3r hatta değil
    Usta olmak istiyorum c3r Adlı Üyenin Profil Grafiği
    Üyelik Tarihi
    11/2008
    Yer
    Monitörün karşısı
    Mesaj
    897

    Alıntı _Onk@_, mesajından alıntı: Mesajı Gör
    Yaklaşık iki gündür araştırma yapıyorum. Tavsiye olunan gidiş yolu ise:
    - İstisna fırlatma ihtimali olan kod bölümü try-catch içine alınmalıdır.
    - İstisna fırlatıldıktan sonra istisnayı fırlatan kod parçasının ayırdığı kaynak ile ilgili geri vermek haricinde işlem yapılmamalıdır.
    evet sefer algan'ın makalesinde okumuştum bende bu yönde,ama ben tıkandım kaldım ilerde antivirüsler,sistem güvenlik ve onarım programları yazmak istiyorum nereden başlıyacağımı çözemedim..şuan sadece küçük programlar yazabiliyorum :S

+ Cevap Yaz

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

     

Bookmarks

Mesaj Yazma Hakları

  • Yeni mesajgöndermezsiniz
  • Cevap yazamazsınız
  • Dosya ekleyemezsiniz
  • Mesajınızı düzenleyemezsiniz