Visualizzazione dei risultati da 1 a 10 su 10
  1. #1
    Utente bannato
    Registrato dal
    Oct 2010
    Messaggi
    1,219

    [c++]Overloading dell' operatore +=

    Ho scritto una classe List (per distinguerla da list) che per ora ha solo le operazioni di pop e di push (proprio come se fosse una pila):
    codice:
    #include <iostream>
    #include <cassert>
    
    using namespace std;
    
    template<class T>
    class List
    {
        public:
        List<T>();
        ~List<T>();
        protected:
        List<T> (T info);
        public:
        void push(T info);
        void pop();
        friend ostream& operator<< (ostream& out, List<T> &l)
        {
            List<T>* ptr=l.next;
            while(ptr!=&l)
            {
                out << *(ptr->info) << "\t";
                ptr=ptr->next;
            }
            return out;
        }
        friend List<T>& operator+= (List<T>& l1, List<T>& l2)
        {
            List<T>* temp=new List<T> ();
            List<T>* ptr;
            ptr=l1.next;
            while(ptr!=&l1)
            {
                temp->push(*(ptr->info));
                ptr=ptr->next;
            }
            ptr=l2.next;
            while(ptr!=&l2)
            {
                temp->push(*(ptr->info));
                ptr=ptr->next;
            }
            return *temp;
        }
        private:
        T *info;
        List <T>* next;
        List <T>* prev;
        int length;
    };
    
    template <class T>
    List<T>::List ()
    {
        info=NULL;
        next=this;
        prev=this;
        length=0;
    }
    
    template<class T>
    List<T>::List (T info)
    {
        next=this;
        prev=this;
        this->info=new T();
        *(this->info)=info;
    }
    
    template<class T>
    List<T>::~List()
    {
        List<T>* ptr, * temp;
        ptr=this->next;
        if(this->info==NULL)
        {
            while(ptr!=this)
            {
                delete ptr->info;
                temp=ptr;
                ptr=ptr->next;
                delete temp;
            }
        }
    }
    
    template<class T>
    void List<T>::push(T info)
    {
        List<T>* ptr,*temp;
        temp=this->prev;
        ptr=new List<T>(info);
        temp->next=ptr;
        ptr->prev=temp;
        this->prev=ptr;
        ptr->next=this;
        length++;
    }
    
    
    template<class T>
    void List<T>::pop()
    {
        List<T>* ptr=this->prev->prev;
        assert(length>0);
        delete this->prev;
        ptr->next=this;
        this->prev=ptr;
        length--;
    }
    
    int main(int argc, char **argv)
    {
        List<int> *l=new List<int>();
        List<int> *l2=new List<int>();
        for(int i=0;i<10;i++)
            l->push(i);
        for(int i=10;i<20;i++)
            l2->push(i);
        *l+=*l2;
        cout<<*l<<endl;
        delete l;
        delete l2;
        return 0;
    }
    Length contiene la lunghezza della lista, non ho avuto problema con l' overloading dell' operatore <<.
    Un problema che ho riscontrato è che sul libro che ho (il Deitel) mi fa l' esempio dell' overloading dell' operatore += passando come argomento solo un parametro, ma se provo a dargli un parametro mi dice che deve per forza avere 2 parametri.
    Ma vengo al sodo: il problema è proprio nel main, quando provo a concatenare due liste (anche s enon mi da nessun errore ne warning):
    codice:
    int main(int argc, char **argv)
    {
        List<int> *l=new List<int>();
        List<int> *l2=new List<int>();
        for(int i=0;i<10;i++)
            l->push(i);
        for(int i=10;i<20;i++)
            l2->push(i);
        *l+=*l2;
        cout<<*l<<endl;
        delete l;
        delete l2;
        return 0;
    }
    Se provo a stampare l mi stampa solo i primi numeri da 0 a 9 anzichè da 0 a 19, in pratica non ha concatenato niente, l' operazione è "sterile".
    Penso che il problema sia provo quando faccio l' overloading:
    codice:
    friend List<T>& operator+= (List<T>& l1, List<T>& l2)
        {
            List<T>* temp=new List<T> ();
            List<T>* ptr;
            ptr=l1.next;
            while(ptr!=&l1)
            {
                temp->push(*(ptr->info));
                ptr=ptr->next;
            }
            ptr=l2.next;
            while(ptr!=&l2)
            {
                temp->push(*(ptr->info));
                ptr=ptr->next;
            }
            return *temp;
        }
    Ma non riesco a capire cosa sbaglio

  2. #2
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Gli operatori si dividono in due categorie: operatori unari e binari.
    Di solito i binari (che prendono due argomenti) sono implementati come friend, gli unari (un solo argomento) come propri della classe.
    Un operatore che può essere solo della classe è operator=() in tutte le sue forme:
    operator=
    operator+=
    operator-=
    etc.

    Quindi sei obbligato rendere quell'operatore menbro di classe.
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  3. #3
    Utente bannato
    Registrato dal
    Oct 2010
    Messaggi
    1,219
    Ecco cosa mi sfuggiva, ho risolto facendolo essere un operatore unario.
    Ma adesso ho un altro problema: ho cambiato il distruttore (anche quello che hoscritto prima mi dava problemi), l' ho scritto così:
    codice:
    template<class T>
    List<T>::~List()
    {
        destroy(this->next);
    }
    template <class T>
    void List<T>::destroy(List<T> *item)
    {
        if(item->info!=NULL)
        {
            destroy(item->next);
            delete item;
        }
    }
    Va in segmentation fault.
    Il perchè mi sfugge il metodo destroy è ricorsivo ma si ferma quando item->info è uguale a NULL, cioè quando incontra la sentinella.
    Il debugger mi dice che è proprio alla riga dove dichiaro delete item, sapete il perchè?

  4. #4
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Il vero problema non è in quelle funzioni, ma nella push.
    Il campo next di this rimane "sporco", pertanto in destroy() arrivi a un punto in cui item avrà quel valore "sporco", la cui successiva indirezione a info da la violazione.

    La soluzione immediata sarebbe:
    codice:
    template<class T>
    void List<T>::push(T info)
    {
        List<T>* ptr,*temp;
        temp=this->prev;
        ptr=new List<T>(info);
        temp->next=ptr;
        ptr->prev=temp;
        this->prev=ptr;
        ptr->next=this;
        this->next = 0;  <-- assegna un valore noto a next
        length++;
    }
    
    template <class T>
    void List<T>::destroy(List<T> *item)
    {
        if(item && item->info!=NULL) <-- controllo che item sia valido.
        {
            destroy(item->next);
            delete item;
        }
    }
    Ti faccio notare però che la push() inserisce sempre ptr nel campo this->prev. E il valore di this non cambia mai tra una push() e l'altra.
    Pertanto l'unica cosa che ottieni è allocare 10 ptr e mantenere solo l'ultimo in memoria, perdendo gli altri 9 per strada.
    Insomma hai memory leak.
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  5. #5
    Utente bannato
    Registrato dal
    Oct 2010
    Messaggi
    1,219
    Ok, ma perchè non deallocare anche il campo info ?

  6. #6
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    In effetti andrebbe deallocato pure lui, ma nel tuo codice non lo fai.
    Io mi sono limitato a individuare il perché tu avessi il problema della violazione d'accesso.
    Tra l'altro la tua lista avrà sempre un solo elemento, proprio in virtù di quel:
    this->prev = ptr;

    A mio avviso dovresti rivedere il design. Una lista è un container di nodi, non un nodo di per se.
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  7. #7
    Utente bannato
    Registrato dal
    Oct 2010
    Messaggi
    1,219
    Si lo so che una lista è un insieme di nodi, quella era un comportamento indesiderato.
    Ho riscritto la classe:
    codice:
    #include <iostream>
    #include <cassert>
    
    using namespace std;
    
    template<class T>
    class List
    {
        private:
        T *info;
        List<T>* next;
        List<T>* prev;
        int length;
        public:
        List<T> ();
        List<T> (T info);
        int size();
        void add(T info,int i);
        friend ostream& operator<< (ostream& out, List<T>& l)
        {
            List<T> *ptr;
            ptr=l.next;
            if(l.info==NULL)
            {
                while(ptr->info!=NULL)
                {
                    out << *(ptr->info) <<"\t";
                    ptr=ptr->next;
                }
            }
            else
            {
                out << *(l.info);
            }
            return out;
        }
        friend istream& operator>> (istream& in, List<T>& l)
        {
            List<T>* ptr;
            ptr=l.next;
            if(l.info==NULL)
            {
                while(ptr->info!=NULL)
                {
                    in >> *(ptr->info);
                    ptr=ptr->next;
                }
            }
            else
            {
                in >> *(l.info);
            }
            return in;
        }
        List<T>& operator[] (int i)
        {
            List<T>* ptr;
            ptr=this->next;
            assert(i< length);
            for(int j=0;j<i;j++)
                ptr=ptr->next;
            return *ptr;
        }
    };
    
    template <class T>
    List<T>::List ()
    {
        next=this;
        prev=this;
        info=NULL;
        length=0;
    }
    
    template <class T>
    List<T>::List(T info)
    {
        next=this;
        prev=this;
        this->info=new T();
        *(this->info)=info;
        length=0;
    }
    
    template<class T>
    int List<T>::size()
    {
        return length;
    }
    
    template<class T>
    void List<T>::add(T info,int i)
    {
        List<T>* t1,*t2,*ptr;
        assert(i<=length);
        ptr=this->next;
        for(int j=0;j<i;j++)
            ptr=ptr->next;
        t1=ptr->prev;
        t2=ptr;
        ptr=new List<T>(info);
        t1->next=ptr;
        ptr->prev=t1;
        ptr->next=t2;
        t2->prev=ptr;
    }
    
    int main(int argc, char **argv)
    {
        List<int> l;
        l.add(5,0);
        l.add(10,0);
        cout<<l;
        return 0;
    }

  8. #8
    Utente bannato
    Registrato dal
    Oct 2010
    Messaggi
    1,219
    Ho un problema con un costruttore:

    codice:
    template <class T>
    List<T>::List(T info)
    {
        next=this;
        prev=this;
        this->info=new T();
        *(this->info)=info;
        length=0;
    }
    Il problema è che il campo info contiene un puntatore, ma per assegnare i campi dichiaro :

    codice:
    *(this->info)=info;
    Ma è una cosa che non funziona per tutti i tipi: ad esempio se creo una lista di stringhe mi va in segmentation fault perchè non è possibile assegnare i valori in questo modo.
    Come faccio a scavalcare questa cosa ? Cioè a fare un assegnamento che sia universale, valido per tutti i tipi di dato?

  9. #9
    Utente di HTML.it
    Registrato dal
    Mar 2009
    Messaggi
    146
    Il problema è che info lo passi per copia così quindi assegni all'elemento una copia creata entrando nella funzione e che poi viene distrutta alla fine della stessa funzione.

    Devi risolvere con un passaggio per riferimento. O con un reference o con un puntatore. L'ho visto al volo non so essere più precisa ora....

  10. #10
    Utente bannato
    Registrato dal
    Oct 2010
    Messaggi
    1,219
    Ho risolto, ho fatto una classe nuova dove il campo info non contiene un puntatore.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.