Duyuruyu Kapat
Facebook Gözat
Twitter Gözat

vector::erase neden nesneyi sonlandirmiyor

Konu, 'C / C++' kısmında acehreli tarafından paylaşıldı.

  1. acehreli

    acehreli Ali Çehreli

    Kayıt:
    19 Ekim 2002
    Mesajlar:
    4,973
    Beğenilen Mesajlar:
    2
    Bir arkadas bana soyle bir soru sordu:

    Asagidaki programin ciktisina bakarsak, vec.erase(it) yapildigi halde o erisicinin gosterdigi nesne sonlanmiyor? Neden cikista "2. Adama Silindi" yazisi tam sondan ikinci for dOngUsunde vec.erase(it) yapildigi anda olmuyor?

    Kod soyle:

    Kod:
    #include <boost/smart_ptr.hpp>
    #include <iostream>
    #include <string>
    #include <vector>
    
    
    
    using namespace std;
    class Adam{
    private:
        string Adi;
    public:
        int No;
        Adam(){
            cout << "Adam Olustu" << endl;
        };
        ~Adam(){
            cout << No << ". Adam Silindi" << endl;
        };
        void SetAdam(int vNo,string isim){
            No = vNo;
            Adi = isim;
            Yaz();
        };
        void Yaz(){
            cout << "Isim =" << Adi << endl;
            cout << "No =" << No << endl;
        };
        void Soyle(){
            cout << No << " numarali adamim. Adim =" << Adi << endl;
        };
    
    };
    
    int main()
    {
        typedef boost::shared_ptr<Adam> CAdamPtr;
    
    
        std::vector<CAdamPtr> vec;
    
        CAdamPtr A1=CAdamPtr(new Adam);
        A1->SetAdam(1,"fatih");
        CAdamPtr A2=CAdamPtr(new Adam);
        A2->SetAdam(2,"fatma");
        CAdamPtr A3=CAdamPtr(new Adam);
        A3->SetAdam(3,"sehide");
        vec.push_back(A1);
        vec.push_back(A2);
        vec.push_back(A3);
    
        cout << "Boyut =" << vec.size() << endl <<endl;
        A2->SetAdam(2,"yeni isim");
        cout << "Boyut =" << vec.size() << endl <<endl;
        A1->Soyle();
        A2->Soyle();
        A3->Soyle();
    
        std::vector<CAdamPtr>::iterator it;
    
        for ( it=vec.begin() ; it < vec.end(); it++ ){
            CAdamPtr temp;
            temp = *it;
            if (temp->No==2){
                vec.erase(it);
                break;
            };
        };
    
        cout << "Boyut =" << vec.size() << endl <<endl;
        for ( it=vec.begin() ; it < vec.end(); it++ ){
            CAdamPtr temp;
            temp = *it;
            temp->Soyle();
        };
    
        cout << "Boyut =" << vec.size() << endl <<endl;
        return 0;
    }
    Cikisin son satirlari soyle oluyor (yerini anlamadigimiz satiri isaretledim):

    Kod:
    ...
    
    1 numarali adamim. Adim =fatih
    2 numarali adamim. Adim =yeni isim
    3 numarali adamim. Adim =sehide
    Boyut =2
    
    1 numarali adamim. Adim =fatih
    3 numarali adamim. Adim =sehide
    Boyut =2
    
    [b]2. Adam Silindi[/b]
    1. Adam Silindi
    3. Adam Silindi

    Ama ciktinin son satirlarinin soyle olacagini dusunurduk:

    Kod:
    ...
    
    1 numarali adamim. Adim =fatih
    2 numarali adamim. Adim =yeni isim
    3 numarali adamim. Adim =sehide
    [b]2. Adam Silindi[/b]
    Boyut =2
    
    1 numarali adamim. Adim =fatih
    3 numarali adamim. Adim =sehide
    Boyut =2
    
    1. Adam Silindi
    3. Adam Silindi
    
    Belki baskalarinin da ilgisini ceker diye buraya da yazdim. Neden vec.erase(it) yapildiginda silinmiyor? :)

    Ali
     
  2. acehreli

    acehreli Ali Çehreli

    Kayıt:
    19 Ekim 2002
    Mesajlar:
    4,973
    Beğenilen Mesajlar:
    2
  3. quasimodo

    quasimodo Daimi Üye

    Kayıt:
    8 Ekim 2006
    Mesajlar:
    737
    Beğenilen Mesajlar:
    0
    Meslek:
    Öğrenci
    Şehir:
    İstanbul
    Bu linkteki verilenleri okuyunca bu soruyu cozecek seviyeye gelmis olur muyuz?
     
  4. acehreli

    acehreli Ali Çehreli

    Kayıt:
    19 Ekim 2002
    Mesajlar:
    4,973
    Beğenilen Mesajlar:
    2
    Hepsini okumaya da gerek yok aslinda. :) Soru boost::shared_ptr'in nesne sayaci bulundurduguyla (reference counting) ve sayac sifira indiginde nesneyi sonlandirdigiyla ilgili...

    Ali
     
  5. quasimodo

    quasimodo Daimi Üye

    Kayıt:
    8 Ekim 2006
    Mesajlar:
    737
    Beğenilen Mesajlar:
    0
    Meslek:
    Öğrenci
    Şehir:
    İstanbul
    Sorunun cozumunu anladim ama belki pek iyi anlatamayabilirim.


    Kod:
    for( it = vec.begin() ; it < vec.end(); it++ ) {
        CAdamPtr temp;
        temp = *it;
    
        if (temp -> No == 2) {
            vec.erase( it );
            break;
        }
    }
    Her dongude yeniden bir temp yaratiliyor. Nesneyi silme isi onu gosteren son
    shared_ptr ' a ait oldugundan vectorden siliniyor ama hala onu gosteren bir
    tane share_ptr oldugundan yikicisi cagirilmiyor. Benim anlamadigim da neden
    ilk seferde 2. nin yikicisi cagiriliyor?
     
  6. acehreli

    acehreli Ali Çehreli

    Kayıt:
    19 Ekim 2002
    Mesajlar:
    4,973
    Beğenilen Mesajlar:
    2
    Evet ama biraz daha dusunmen gerekiyor! :)

    temp'in sayaci bir arttirdigi konusunda haklisin tabii, ama kendisi dOngU sonlandiginda sonlandigi icin sayaci hemen tekrar da eksiltir.

    shared_ptr'in sayac degerini use_count() ile ogrenebilirsin. Ornegin Soyle() fonksiyonunu onu da soyleyecek sekilde degistirsen ve son dOngUde soyle cagirsan:

    Kod:
        // ilgisiz: sabit nesneler icin de cagrilabilmesi icin 'const' olsa iyi olur
        void Soyle(size_t sayac) const {
            cout << No << " numarali adamim. Adim =" << Adi << endl;
            cout << "sayac: " << sayac << endl;
        };
    
    /* ... */
    
        // ilgisiz: it < vec.end() yerine daha genel olan it != vec.end() de kullandim
        for ( it=vec.begin() ; it != vec.end(); it++ ){
            CAdamPtr temp;
            temp = *it;    // [Ali] Bu kopya nedeniyle sayac 1 artiyor
            temp->Soyle(temp.use_count());
        }; // [Ali] temp sonlaninca sayac yine 1 eksiliyor
    
    Bende ciktinin o bolumu soyle oldu:

    Kod:
    1 numarali adamim. Adim =fatih
    sayac: 3
    3 numarali adamim. Adim =sehide
    sayac: 3
    Boyut =2
    
    Bir kopya vector'de ve bir kopya temp'te... Ucuncusu nerede? :)

    Ali
     
  7. quasimodo

    quasimodo Daimi Üye

    Kayıt:
    8 Ekim 2006
    Mesajlar:
    737
    Beğenilen Mesajlar:
    0
    Meslek:
    Öğrenci
    Şehir:
    İstanbul
    push_back() ilgili birsey mi ?
     
  8. acehreli

    acehreli Ali Çehreli

    Kayıt:
    19 Ekim 2002
    Mesajlar:
    4,973
    Beğenilen Mesajlar:
    2
    push_back shared_ptr'in bir kopyasini aliyor ve vector icinde tutuyor. Bundan baska bir etkisi yok. Dolayisiyla sonucta sayacin bir adedi vector icinde... Bir tanesi temp... Otekisi de sana bakiyor... :p

    Ali
     
  9. quasimodo

    quasimodo Daimi Üye

    Kayıt:
    8 Ekim 2006
    Mesajlar:
    737
    Beğenilen Mesajlar:
    0
    Meslek:
    Öğrenci
    Şehir:
    İstanbul
    A2->SetAdam(2,"fatma");
    burada bir tane var
    vectorun icinde bir kopyasi var,
    birde temp te kopyasi var?
     
  10. acehreli

    acehreli Ali Çehreli

    Kayıt:
    19 Ekim 2002
    Mesajlar:
    4,973
    Beğenilen Mesajlar:
    2
    Dogru! :) Yani A1, A2, ve A3 de shared_ptr olduklari icin onlar yasadigi surece nesneler de yasamaya devam ediyorlar.

    Programi kendimce biraz degistirdim. Bunda A1, A2, ve A3 yok. SetAdam()'i da kaldirdim:

    Kod:
    #include <boost/shared_ptr.hpp>
    #include <iostream>
    #include <string>
    #include <vector>
    
    using namespace std;
    
    class Adam
    {
        string Adi;
        int No;
    
    public:
    
        Adam(int vNo, const string & isim)
            :
            Adi(isim),
            No(vNo)
        {
            cout << "Adam Olustu: " << Adi << endl;
        }
        
        ~Adam() {
            cout << No << ". Adam Silindi" << endl;
        }
    
        int Numarasi() const {
            return No;
        }
    
        void Yaz() const {
            cout << "Isim =" << Adi << endl;
            cout << "No =" << No << endl;
        }
    
        void Soyle() const {
            cout << No << " numarali adamim. Adim =" << Adi << endl;
        }
    };
    
    int main()
    {
        typedef boost::shared_ptr<Adam> CAdamPtr;
    
        std::vector<CAdamPtr> vec;
        vec.push_back(CAdamPtr(new Adam(1, "fatih")));
        vec.push_back(CAdamPtr(new Adam(2, "fatma")));
        vec.push_back(CAdamPtr(new Adam(3, "sehide")));
    
        cout << "Boyut =" << vec.size() << endl <<endl;
        vec[1] = CAdamPtr(new Adam(2,"yeni isim"));
        cout << "Boyut =" << vec.size() << endl <<endl;
        vec[0]->Soyle();
        vec[1]->Soyle();
        vec[2]->Soyle();
    
        std::vector<CAdamPtr>::iterator it;
    
        for ( it=vec.begin() ; it != vec.end(); it++ ){
            CAdamPtr temp;
            temp = *it;
            if (temp->Numarasi() == 2){
                vec.erase(it);
                break;
            };
        };
    
        cout << "Boyut =" << vec.size() << endl <<endl;
        for ( it=vec.begin() ; it < vec.end(); it++ ){
            CAdamPtr temp;
            temp = *it;
            temp->Soyle();
        };
    
        cout << "Boyut =" << vec.size() << endl <<endl;
        return 0;
    }
    Ali
     
  11. quasimodo

    quasimodo Daimi Üye

    Kayıt:
    8 Ekim 2006
    Mesajlar:
    737
    Beğenilen Mesajlar:
    0
    Meslek:
    Öğrenci
    Şehir:
    İstanbul
    Sormayi unuttum ama neden 2. nin yikicisi once cagriliyor?

    Tahmini cavap :
    Cunku son noktaya gelindiginde A2 den 1 tane var digerlerinden 2 ser tane var?
     
  12. acehreli

    acehreli Ali Çehreli

    Kayıt:
    19 Ekim 2002
    Mesajlar:
    4,973
    Beğenilen Mesajlar:
    2
    Dogru ama yeterli cevap degil! :)

    Asil programda A2'nin tanimini vec'ten onceye al; yani tek bir satirin yerini degistir:

    Kod:
        CAdamPtr A2=CAdamPtr(new Adam);
        std::vector<CAdamPtr> vec;
    
    Simdi cikisin sonu soyle oluyor:

    Kod:
    1. Adam Silindi
    3. Adam Silindi
    2. Adam Silindi
    
    Ali
     
  13. khaos

    khaos Yeni Üye

    Kayıt:
    17 Ocak 2007
    Mesajlar:
    3
    Beğenilen Mesajlar:
    0
    Ben bu yontemi sunun icin kullanıyorum. Bir container icinde saklayacagım elemanları, cok farklı dosya ve fonksiyonlar icinde olusturduktan sonra container icinde saklamak istiyorum. Ben baska bi şekilde cozemedim. O yuzden shared_ptr en iyi cozum gibi geldi bana. Bu yontemi OGRE icinde gormustum. Ama OGRE nın tamamını incelemedigim icin anlamamıstım. Sonra bi arkadas shared_ptr den bahsedince kafamdaki ampul yandı :)
     
  14. khaos

    khaos Yeni Üye

    Kayıt:
    17 Ocak 2007
    Mesajlar:
    3
    Beğenilen Mesajlar:
    0
    Arkadaslar, bu konunun devamı olarak soyle bi sorusormak istiyorum. Shared_ptr olarak tanımlanan degişkenimi, program sonlanmadan , ihtiyacım oldugu anda sonlandırmak istiyorum. Bunu nasıl yapacagım? Yani use_count() sadece 1 dondurdugunde nasıl sonlandıracagım..?
     
  15. acehreli

    acehreli Ali Çehreli

    Kayıt:
    19 Ekim 2002
    Mesajlar:
    4,973
    Beğenilen Mesajlar:
    2
    Herhangi bir shared_ptr'in reset()'ini cagirabilirsin. O zaman "NULL isaretci" gibi olur ve eger son sahip oysa, zaten nesneyi sonlandirir:

    p.reset();

    Ali
     
  16. khaos

    khaos Yeni Üye

    Kayıt:
    17 Ocak 2007
    Mesajlar:
    3
    Beğenilen Mesajlar:
    0
    tamam ustadım. demek resetin gorevini yanlıs anlamısım. teşekkur ederim