Iterator:perchè il primo elemento stampato...

di il
6 risposte

Iterator:perchè il primo elemento stampato...

Sto provando a studiare bene gli iteratori (per risolvere questo https://www.iprogrammatori.it/forum-programmazione/cplusplus/sono-punto-morto-proseguire-riniziare-sigsegv-t17688.html)e ho scritto questo programma per provare :

#include <iostream>
#include "lista_interna.h"

using namespace std;

int main()
{
    lista_interna prova;
    prova.Impostainizio();
    prova.Vaiindietro();
    cout<<prova.RestituisciValorePuntato()<<endl;
    prova.Vaiavanti();
    cout<<prova.RestituisciValorePuntato()<<endl;
    prova.Vaiavanti();
    cout<<prova.RestituisciValorePuntato()<<endl;
    return 0;
}
intestazione lista_interna:
#ifndef LISTA_INTERNA_H
#define LISTA_INTERNA_H
#include <list>

using namespace std;

class lista_interna
{
    public:
        lista_interna();
        virtual ~lista_interna();

        void Aggiungi(int numero);
        int RestituisciValorePuntato();
        void Vaiavanti();
        void Vaiindietro();
        void Impostainizio();

    private:
        list<int> lista_int;
        list<int>::iterator ind_int;
        int numeri;


};

#endif // LISTA_INTERNA_H
sorgente lista_interna:

#include "lista_interna.h"

lista_interna::lista_interna()
{
    numeri=0;
}

lista_interna::~lista_interna()
{

}

void lista_interna::Aggiungi(int numero)
{
    lista_int.push_back(numero);
    numeri++;
}

int lista_interna::RestituisciValorePuntato()
{
    int risultato=0;
    risultato=*ind_int;
    return risultato;
}

void lista_interna::Vaiavanti()
{
    ind_int++;
}

void lista_interna::Vaiindietro()
{
    ind_int--;
}

void lista_interna::Impostainizio()
{
    ind_int=lista_int.begin();
}
Ho provato anche a inserire dei dati nella lista ma stampa sempre il numero 2686704 insieme agli altri.
Ho visto durante il Debug che nella prima stampa ,nonostane l'iteratore sia sulla prima posizione ,cambia indirizzo e valore... com'è possibile?

6 Risposte

  • Re: Iterator:perchè il primo elemento stampato...

    Se non inserisci dati i valori ottenuti sono casuali, inoltre arretrare un iterator ottenuto da una begin() ha comportamento indefinito, ergo può succedere di tutto. Con gli iterator puoi spostarti solo nell'intervallo compreso tra [ begin() - end() ): ne prima ne dopo avrai qualcosa di valido.
  • Re: Iterator:perchè il primo elemento stampato...

    shodan ha scritto:


    Se non inserisci dati i valori ottenuti sono casuali, inoltre arretrare un iterator ottenuto da una begin() ha comportamento indefinito, ergo può succedere di tutto. Con gli iterator puoi spostarti solo nell'intervallo compreso tra [ begin() - end() ): ne prima ne dopo avrai qualcosa di valido.
    Mi sono spiegato male

    Scrivendo cosi:
    #include <iostream>
    #include "lista_interna.h"
    
    using namespace std;
    
    int main()
    {
        lista_interna prova;
        prova.Impostainizio();
        prova.Aggiungi(1);
        prova.Aggiungi(2);
        prova.Aggiungi(3);
        cout<<prova.RestituisciValorePuntato()<<endl;
        prova.Vaiavanti();
        cout<<prova.RestituisciValorePuntato()<<endl;
        prova.Vaiavanti();
        cout<<prova.RestituisciValorePuntato()<<endl;
        return 0;
    }
    
    l'output è:
    2686704
    1
    2
    
    Process returned 0 (0x0)   execution time : 0.031 s
    Press any key to continue.

    notare che da sempre quel numero , potrebbe essere una codifica di qualche tipo di errore?
    Un'altra domanda : ma la lista dichiarata in quel modo non è bidirezionale ? facendo il debug a me risultano all'interno dell iteratore due indirizzi uno avanti e uno indietro.
    Apparentemente andare avanti e indietro funziona infatti usando:
    #include <iostream>
    #include "lista_interna.h"
    
    using namespace std;
    
    int main()
    {
        lista_interna prova;
        prova.Impostainizio();
        prova.Aggiungi(1);
        prova.Aggiungi(2);
        prova.Aggiungi(3);
        cout<<prova.RestituisciValorePuntato()<<endl;
        prova.Vaiindietro();
        cout<<prova.RestituisciValorePuntato()<<endl;
        prova.Vaiindietro();
        cout<<prova.RestituisciValorePuntato()<<endl;
        return 0;
    }
    
    2686704
    3
    2
    
    Process returned 0 (0x0)   execution time : 0.842 s
    Press any key to continue.
    quindi va sia avanti che indietro ma come primo output stampa quel numero 2686704

    addiritura se scrivo :
    #include <iostream>
    #include "lista_interna.h"
    
    using namespace std;
    
    int main()
    {
        lista_interna prova;
        prova.Impostainizio();
        prova.Aggiungi(1);
        prova.Aggiungi(2);
        prova.Aggiungi(3);
        prova.Vaiindietro();
        cout<<prova.RestituisciValorePuntato()<<endl;
        prova.Vaiavanti();
        cout<<prova.RestituisciValorePuntato()<<endl;
        prova.Vaiavanti();
        cout<<prova.RestituisciValorePuntato()<<endl;
        return 0;
    }
    
    l'output è:
    3
    2686704
    1
    
    Process returned 0 (0x0)   execution time : 0.016 s
    Press any key to continue.
    Pare che venga messo questo numero in cima alla lista .
    Se però vado avanti prima di una posizione allora va tutto bene.

    Se tu mi dici che questo non dovrebbe accadere e che dovrebbero esserci dei valori casuali; la spiegazione puo essere il compilatore? Uso mingw32-g++.exe con code::blocks
  • Re: Iterator:perchè il primo elemento stampato...

    Stai facendo un grossolano errore concettuale: prima si aggiungono gli elementi, poi si ottiene l'iteratore al primo elemento. Tu invece stai facendo esattamente l'opposto e dato che il primo elemento non esiste nella lista, ottieni un valore "strano" (può dipendere dall'implementazione della libreria se tale valore è un codice d'errore, è casuale oppure viene lanciato un assert).

    Concettualmente è come essere all'interno di una stanza i cui muri sono begin() - end() (escluso).
    Puoi muoverti all'interno della stanza ma non passare attraverso i muri, perché se lo fai (rompendoli) rischi che ti cada il soffito in testa.

    La lista è bidirezionale, ma la bidirezionalità è valida solo nell'intervallo [ begin() - end() ) come ti ho detto. Il compilatore può effettuare una diagnostica per accertarsi che tale intervallo sia rispettato. Se fai un begin()-- o un end()++ (cosa che può accadere se decrementi o incrementi l'iteratore con ++ o --), in debug può essere lanciato un assert, in release hai un crash.
    Il tuo main deve essere:
    
    int main()
    {
        lista_interna prova;
        prova.Aggiungi(1);
        prova.Aggiungi(2);
        prova.Aggiungi(3);
        prova.Impostainizio();
        cout<<prova.RestituisciValorePuntato()<<endl; // 1
        prova.Vaiavanti();
        cout<<prova.RestituisciValorePuntato()<<endl; // 2
        prova.Vaiavanti();
        cout<<prova.RestituisciValorePuntato()<<endl; // 3
    
        prova.Vaiavanti(); // superato intervallo valido
        cout<<prova.RestituisciValorePuntato()<<endl; // BOOM!
    
        return 0;
    }
    
  • Re: Iterator:perchè il primo elemento stampato...

    Aaaaaaaaah ecco !!!! ora va grazie:)
    ma non ho capito perchè dopo se vado ancora avanti riparte dall'inizio.
    
    1
    2
    3
    2686704
    1
    2
    
    Process returned 0 (0x0)   execution time : 0.031 s
    Press any key to continue.
    

    Quindi se voglio usare una lista devo per forza ogni volta rinizializarne l'iteratore dopo l'introduzione?
    come posso farlo in un problema tipo quello che dicevo in cima, dove in un punto mi serve passare un elemento nella lista per volta e poi andare al successivo?
    perchè li avviene il SIGSEGV e credo per una questione di uso errato degli iteratori.

    Sapresti dove trovare del materiale per studiarmeli meglio ? più che altro per saper come funziona e non come usarlo e basta:)
  • Re: Iterator:perchè il primo elemento stampato...

    ma non ho capito perchè dopo se vado ancora avanti riparte dall'inizio.
    E' undefined behaviour, cioè il tuo compilatore non prevede diagnostica in debug (scherzando, ma non troppo, il compilatore potrebbe anche formattarti l'hd e sarebbe un comportamento corretto per lo standard).
    Quindi se voglio usare una lista devo per forza ogni volta rinizializarne l'iteratore dopo l'introduzione?
    No, è sufficiente un elemento per avere il primo iterator della lista valido. Ma è meglio inserire prima tutti gli elementi e poi ottenere gli iteratori. Infatti se per begin() basta un elemento, l'iterator end() varia a seconda di quanti elementi contiene la lista.
    perchè li avviene il SIGSEGV e credo per una questione di uso errato degli iteratori.

    L'errore avviene perché incrementi l'iteratore senza controllare che sia valido.
    
        for(int k=0;k<ultimo_estratto;k++)
            Sommario::i++;
    
    corretto è:
    
        for(int k=0;k<ultimo_estratto [color=#FF0000]&& i != capitoli.end()[/color];k++)
            Sommario::i++;
    
    Attento poi che list::erase può inficiare tutti gli iteratori ottenuti. Se lo fai, la successiva istruzione dovrà essere una begin() per riottenere l'iteratore iniziale.
    Sapresti dove trovare del materiale per studiarmeli meglio ?
    In italiano non ho niente. In inglese puoi scaricare il Thinking in C++ vol. 2 di Bruce Eckel, liberamente disponibile nel suo sito (o attraverso di esso).
    C'è un'intera sezione dedicata agli iteratori.
  • Re: Iterator:perchè il primo elemento stampato...

    Eh mi tocca imparare bene l'inglese ... cmq il controllo non fatto l'avevo gia messo in conto ,ma non sapevo come scriverlo grazie per il suggerimento(fosse stato per me avrei "spacchettato" il for in while). Comunque il SIGSEGV appare all'apertura del primo valore, nonostante la stampa di prova (ad un certo punta mi diventa impossibile e stressante esaminare i dati dal watches) dimostra che gli elementi ci sono ... boh mi sa che quel progetto lo lascio li fino a quando non avrò fatto un po' di esperienza e studiato bene bene ... alla fine è solo 1 mese che metto mano al c++ quindi non mi lamento... intanto ho fatto a mano per questa l'estate, scoprendo che molte cose potrebbero essere rimosse dal progetto:)

    Grazie di cuore
Devi accedere o registrarti per scrivere nel forum
6 risposte