Domanda [HELP] gestione ram dinamica

Stato
Discussione chiusa ad ulteriori risposte.

Simur Birkoff

Utente Gold
17 Febbraio 2014
797
29
302
321
Salve! Studiavo l'heap memory e la relativa gestione dei puntatori. Qualche punto mi sfugge. Posto un piccolo codice a cui sono arrivato per tentativi ma non credo di aver compreso appieno il suo significato!
Ciò che cerco di fare e creare una lista dinamica di struct:

PHP:
#include<iostream>
#include<string>
using namespace std;

struct mp3
{
  string titolo;
  string autore;
  int durata;
  int voto;
  
  mp3 *succ; 
};

int main()
{
  mp3 *il=NULL; 

  il=new mp3;  
  
  il->succ=NULL;   
  il->titolo="adagio";
  il->autore="Fabian Lara";
  il->durata=201;
  il->voto=9;
//----------------------------------------------------------------------------------------------------------------------------------- 
  mp3 *p2=NULL;  
  
  p2=new mp3;
  
  p2->succ=il;  
  p2->titolo="M3";
  p2->autore="Noyz Narcos";
  p2->durata=142;
  p2->voto=8;
  
  il=p2;
  
 return 0;  
}

Ora, qual è il significato della struct autoreferenziata?
Perchè
il=p2 ?
Capisco che stiamo parlando di indirizzi di memoria compatibili, non riesco però a collocare l'assegnazione nel contesto del codice. Ma più in generale, parliamo della gestione dinamica della ram per creare strutture non prettamente lineari come vettori e matrici.
Grazie mille!
:)
 
Ultima modifica:
Ora, qual è il significato della struct autoreferenziata?
Non è una struct autoreferenziata, è una struttura dati chiamata linked list.
Il succo di questa struttura dati è: aggiungi ad ogni elemento della lista, il puntatore all'elemento successivo (la reference quindi non è a se stessa). Questo sistema ti permette di scorrere tutta la lista partendo da un unico puntatore e senza creare un array.
Mi pare che qui su inforge ci siano un paio di mini-guide sulle linked list, o comunque c'è più di un topic a riguardo. Prova a dare un'occhiata con il cerca.

Perchè il=p2 ?
Per creare un memory leak. Se quella riga non ci fosse sarebbe meglio, comunque in generale vale la regola "ad ogni new deve corrispondere una delete". Nel tuo caso te ne puoi infischiare perché le delete sarebbero l'ultima istruzione ad essere eseguita, quindi la memoria che recuperi con il delete alla fine la recupereresti ugualemente con la chiusura del programma, ma generalmente conviene farci molta attenzione. Per esempio il famigerato consumo di memoria spaventosamente alto di firefox (di qualche anno fa) era dovuto proprio a questo, ma in generale è un problema comunissimo nei linguaggi senza garbage collector.

strutture non prettamente lineari come vettori e matrici.
A dire il vero i vettori e (soprattutto) le matrici sono lineari in memoria. Solitamente l'allocazione dinamica per delle liste si usa quando si ha a che fare con elementi di dimensioni considerevoli, oppure per sfruttare qualche algoritmo particolare (es. binary search tree).

Se c'è qualcosa in particolare che non hai capito chiedi pure, così su due piedi non mi viene in mente niente da aggiungere.
 
  • Mi piace
Reazioni: Internauta
Non è una struct autoreferenziata, è una struttura dati chiamata linked list.
Il succo di questa struttura dati è: aggiungi ad ogni elemento della lista, il puntatore all'elemento successivo (la reference quindi non è a se stessa). Questo sistema ti permette di scorrere tutta la lista partendo da un unico puntatore e senza creare un array.
Mi pare che qui su inforge ci siano un paio di mini-guide sulle linked list, o comunque c'è più di un topic a riguardo. Prova a dare un'occhiata con il cerca.


Per creare un memory leak. Se quella riga non ci fosse sarebbe meglio, comunque in generale vale la regola "ad ogni new deve corrispondere una delete". Nel tuo caso te ne puoi infischiare perché le delete sarebbero l'ultima istruzione ad essere eseguita, quindi la memoria che recuperi con il delete alla fine la recupereresti ugualemente con la chiusura del programma, ma generalmente conviene farci molta attenzione. Per esempio il famigerato consumo di memoria spaventosamente alto di firefox (di qualche anno fa) era dovuto proprio a questo, ma in generale è un problema comunissimo nei linguaggi senza garbage collector.


A dire il vero i vettori e (soprattutto) le matrici sono lineari in memoria. Solitamente l'allocazione dinamica per delle liste si usa quando si ha a che fare con elementi di dimensioni considerevoli, oppure per sfruttare qualche algoritmo particolare (es. binary search tree).

Se c'è qualcosa in particolare che non hai capito chiedi pure, così su due piedi non mi viene in mente niente da aggiungere.

Intendevo dire "le matrici e i vettori sono lineari, come construire qualcosa di non lineare?"
In ogni caso, ora cerco qualcosa come consigliato! Nel caso avrò ulteriori domande specifiche! :) Grazie
 
Ultima modifica:
Che significa? L'hai scritto tu, quindi saprai tu il perchè...

In ogni caso la new alloca per definizione un'area di memoria dinamica.

Ci sono arrivato per tentativi! E' la dichiarazione che mi permette di acquisire l'indirizzo di memoria di p2 in il e passare al nodo successivo!
Ti faccio un esempio:

codice non funzionante. Errore:

Codice:
72:43: error: no matching function for call to ‘inventario::import(oggetto**, oggetto**, std::vector<std::basic_string<char> >&)’

Te lo posto, se hai voglia di darci un occhiata e magari farmi qualche correzione mi faresti un gran favore! Ovviamente vale anche per @St3ve
Vi ringrazio molto!

PHP:
#include<string>
#include<iostream>
#include<vector>
#include<fstream>
#include<cstdlib>
using namespace std;

class inventario
{
  struct oggetto
  {
    string nome;
    string utilizzo;
    string comando;
    
    oggetto *succ;
  };
  oggetto *hd;
  oggetto *tl;
  
  string obj;
  
  vector<string> vettore;
  
public:
  //void update(oggetto *hd, oggetto *tl, string obj);
  void import(oggetto *hd, oggetto *tl, vector<string> vettore)
  {
    int i=1;
    string linea;
    ifstream file("database/inventario.txt");
    
    vettore[0]="inventario\0";
    
    while(getline(file, linea))
      vettore.push_back(linea);
    
    do
    {
      tl->nome=vettore[i];
      tl->utilizzo=vettore[i+1];
      tl->comando=vettore[i+2];
      
      tl->succ=new oggetto;
      tl=tl->succ;
      
      i=i+3;
      
    } while(i<vettore.size());

  }
};

struct oggetto
{
  string nome;
  string utilizzo;
  string comando;
  
  oggetto *succ;
};

int main()
{
  inventario inventario;
  vector<string> vettore;
  oggetto *testa;
  oggetto *coda;
  testa=new oggetto;
  coda=testa;
  
  inventario.import(&testa, &coda, vettore);  //errore in questa linea
  
  while (coda!=NULL) 
  {
    cout<< coda->nome <<"  \n";  
    cout<< coda->utilizzo <<"  \n"; 
    cout<< coda->comando <<"  \n"; 
    coda= coda->succ;
  }
    
  
 return 0; 
}

Il programma deve pescare linea per linea di un file, piazzarle una per una in un vector di stringhe e poi creare una lista dinamica di struct dove ogni elemento delle struct concatenate è riampito con una specifica stringa del vector e quindi del file!
Sicuramente si può ottenere lo stesso risultato mooolto più facilmente, ma questo è un codice esercizio o, come dice St3ve, "giocattolo" e mi sarebbe proprio utile comprenderlo in questa forma!
Grazie! :)
 
Sicuramente si può ottenere lo stesso risultato mooolto più facilmente, ma questo è un codice esercizio o, come dice St3ve, "giocattolo" e mi sarebbe proprio utile comprenderlo in questa forma!

I miei commenti sono in maiuscolo, non ho testato il codice. Ho cercato di lasciarlo molto fedele all'originale quindi c'è ancora qualcosa che non quadra molto, più che altro l'ho fatto per segnalarti gli errori.
Codice:
#include<string>
#include<iostream>
#include<vector>
#include<fstream>
#include<cstdlib>
using namespace std;

struct oggetto
{
    string nome;
    string utilizzo;
    string comando;
  
    oggetto *succ;
};

class inventario
{
    // struct oggetto      // RINDONDANZA INUTILE, BASTA DEFINIRE PRIMA LA STRUCT
    // {
    // string nome;
    // string utilizzo;
    // string comando;
    //  
    // oggetto *succ;
    // };
    oggetto *hd;
    oggetto *tl;
  
    string obj;
  
    vector<string> vettore;
  
public:
    //void update(oggetto *hd, oggetto *tl, string obj);
    // void import(oggetto *hd, oggetto *tl, vector<string> vettore) 
    // hd, tl E vettore NON SONO I CAMPI (VARIABILI) DELLA CLASSE, SONO DEI PARAMETRI CON LO STESSO NOME DELLE VARIABILI MEMBRO, MA SONO COMPLETAMENTE DIFFERENTI
    void import()  // CORREZIONE
    {
        // int i=1;
        string linea;
        ifstream file("database/inventario.txt");
    
        //vettore[0]="inventario\0";   // CHI TE LO DICE CHE HAI GIÀ UN ELEMENTO NEL VETTORE? vettore.size() È 0.
        vettore.push_back("inventario"); // CORREZIONE
    
        while(getline(file, linea))
            vettore.push_back(linea);

        if(hd == NULL)       // CORREZIONE VEDI (*)
        {
            hd = new oggetto(); // SE NON ESISTE UNA TESTA, LA CREO
            tl = hd;            // HO APPENA CREATO LA TESTA, SONO AL PRIMO ELEMENTO E DI CONSEGUENZA LA MIA TESTA È ANCHE LA CODA
        }
        else
        {
            tl->succ = new oggetto(); // ESISTE GIÀ UN ELEMENTO: AGGIUNGO UN NUOVO OGGETTO. VEDI (**)
            tl = tl->succ;            // SPOSTO LA CODA AL SUO ELEMENTO SUCCESSIVO
        }

        //do     // CHI TE LO DICE CHE IL FILE NON SIA VUOTO?
        for(int i=1; i<vettore.size(); i+=3) // A DIRE IL VERO NEMMENO COSÌ SAREBBE PERFETTO, MA SORVOLIAMO...
        {
            
            tl->nome=vettore[i];       // (*) CHI TE LO DICE CHE tl SIA GIÀ INIZIALIZZATO?
            tl->utilizzo=vettore[i+1];
            tl->comando=vettore[i+2];
      
            // tl->succ=new oggetto;  // (**) CHI TE LO DICE CHE C'È UN ELEMENTO SUCCESSIVO? 
            // tl=tl->succ;
            // i=i+3;
        } //while(i<vettore.size()); 
    }

    oggetto *getHead()  // VEDI (***)
    {
        return hd;
    }
};


int main()
{
    inventario inventario;
    //vector<string> vettore; // NON HANNO SENSO
    //oggetto *testa;   
    //oggetto *coda;
    //testa=new oggetto;
    //coda=testa;
  
    //inventario.import(&testa, &coda, vettore);  //errore in questa linea
    inventario.import();
    oggetto *coda = inventario.getHead(); // (***) LA TESTA È CONTENUTA NELLA CLASSE INVENTARIO
  
    while (coda!=NULL) 
    {
        cout<< coda->nome <<"  \n";  // OPPURE: inventario.getHead()->nome;  O ANCORA MEGLIO CREARE UN METODO stampaInventario()
        cout<< coda->utilizzo <<"  \n"; 
        cout<< coda->comando <<"  \n"; 
        coda= coda->succ;
    }
    
    return 0; 
}


Questo invece è un modo un po' più opportuno per farlo, ma rimanendo sempre sullo stile che avevi in mente:
Codice:
#include<string>
#include<iostream>
#include<fstream>

using namespace std;

struct elemento
{
    string nome;
    string utilizzo;
    string comando;
    
    elemento *next;
};

class inventario
{
private:
    elemento *head, *tail;
  
public:
    elemento *pushElemento(string nome, string utilizzo, string comando)
    {
        // aggiungo un pezzo alla coda (o inizializzo la testa)
        if(head == NULL)
        {
            head = new elemento();
            tail = head;
        }
        else
        {
            tail->next = new elemento();
            tail = tail ->next;
        }
        
        // inizializzo l'elemento
        tail->nome = nome;
        tail->utilizzo = utilizzo;
        tail->comando = comando;
    }

    void import(string filename)  
    {
        ifstream file(filename.c_str()); // a dire il vero basta filename

        string nome, utilizzo, comando;

        do
        {
            getline(file, nome);
            getline(file, utilizzo);
            getline(file, comando);

            pushElemento(nome, utilizzo, comando);
        } while(file.rdstate() == ios_base::goodbit); // non sono sicuro se funziona, prova...
    }
    
    void printList()
    {
        elemento *tmp = head;
        while(tmp != NULL)
        {
            cout << "nome: " << tmp->nome << "\n"
                 << "utilizzo: " << tmp->utilizzo << "\n"
                 << "comando: " << tmp->comando << "\n" << "\n";

            tmp = tmp->next;
        }
    }

    ~inventario()
    {
        // nota: il tuo inventario lasciava tutta la lista in memoria, qui non ci sono memory leaks.
        elemento *tmp;
        while((tmp = head) != NULL)
        {
            head = head->next;
            delete tmp;
        }
    }
};


int main()
{
    inventario inventario;

    inventario.import("database/inventario.txt");
    inventario.printList();
    
    return 0; 
}

BTW: nemmeno questo è testato, a dire il vero non avevo voglia di creare il file da importare xD però anche se c'è qualcosa da ritoccare il senso credo che si capisca.
 
I miei commenti sono in maiuscolo, non ho testato il codice. Ho cercato di lasciarlo molto fedele all'originale quindi c'è ancora qualcosa che non quadra molto, più che altro l'ho fatto per segnalarti gli errori.
Codice:
#include<string>
#include<iostream>
#include<vector>
#include<fstream>
#include<cstdlib>
using namespace std;

struct oggetto
{
    string nome;
    string utilizzo;
    string comando;
  
    oggetto *succ;
};

class inventario
{
    // struct oggetto      // RINDONDANZA INUTILE, BASTA DEFINIRE PRIMA LA STRUCT
    // {
    // string nome;
    // string utilizzo;
    // string comando;
    //  
    // oggetto *succ;
    // };
    oggetto *hd;
    oggetto *tl;
  
    string obj;
  
    vector<string> vettore;
  
public:
    //void update(oggetto *hd, oggetto *tl, string obj);
    // void import(oggetto *hd, oggetto *tl, vector<string> vettore) 
    // hd, tl E vettore NON SONO I CAMPI (VARIABILI) DELLA CLASSE, SONO DEI PARAMETRI CON LO STESSO NOME DELLE VARIABILI MEMBRO, MA SONO COMPLETAMENTE DIFFERENTI
    void import()  // CORREZIONE
    {
        // int i=1;
        string linea;
        ifstream file("database/inventario.txt");
    
        //vettore[0]="inventario\0";   // CHI TE LO DICE CHE HAI GIÀ UN ELEMENTO NEL VETTORE? vettore.size() È 0.
        vettore.push_back("inventario"); // CORREZIONE
    
        while(getline(file, linea))
            vettore.push_back(linea);

        if(hd == NULL)       // CORREZIONE VEDI (*)
        {
            hd = new oggetto(); // SE NON ESISTE UNA TESTA, LA CREO
            tl = hd;            // HO APPENA CREATO LA TESTA, SONO AL PRIMO ELEMENTO E DI CONSEGUENZA LA MIA TESTA È ANCHE LA CODA
        }
        else
        {
            tl->succ = new oggetto(); // ESISTE GIÀ UN ELEMENTO: AGGIUNGO UN NUOVO OGGETTO. VEDI (**)
            tl = tl->succ;            // SPOSTO LA CODA AL SUO ELEMENTO SUCCESSIVO
        }

        //do     // CHI TE LO DICE CHE IL FILE NON SIA VUOTO?
        for(int i=1; i<vettore.size(); i+=3) // A DIRE IL VERO NEMMENO COSÌ SAREBBE PERFETTO, MA SORVOLIAMO...
        {
            
            tl->nome=vettore[i];       // (*) CHI TE LO DICE CHE tl SIA GIÀ INIZIALIZZATO?
            tl->utilizzo=vettore[i+1];
            tl->comando=vettore[i+2];
      
            // tl->succ=new oggetto;  // (**) CHI TE LO DICE CHE C'È UN ELEMENTO SUCCESSIVO? 
            // tl=tl->succ;
            // i=i+3;
        } //while(i<vettore.size()); 
    }

    oggetto *getHead()  // VEDI (***)
    {
        return hd;
    }
};


int main()
{
    inventario inventario;
    //vector<string> vettore; // NON HANNO SENSO
    //oggetto *testa;   
    //oggetto *coda;
    //testa=new oggetto;
    //coda=testa;
  
    //inventario.import(&testa, &coda, vettore);  //errore in questa linea
    inventario.import();
    oggetto *coda = inventario.getHead(); // (***) LA TESTA È CONTENUTA NELLA CLASSE INVENTARIO
  
    while (coda!=NULL) 
    {
        cout<< coda->nome <<"  \n";  // OPPURE: inventario.getHead()->nome;  O ANCORA MEGLIO CREARE UN METODO stampaInventario()
        cout<< coda->utilizzo <<"  \n"; 
        cout<< coda->comando <<"  \n"; 
        coda= coda->succ;
    }
    
    return 0; 
}


Questo invece è un modo un po' più opportuno per farlo, ma rimanendo sempre sullo stile che avevi in mente:
Codice:
#include<string>
#include<iostream>
#include<fstream>

using namespace std;

struct elemento
{
    string nome;
    string utilizzo;
    string comando;
    
    elemento *next;
};

class inventario
{
private:
    elemento *head, *tail;
  
public:
    elemento *pushElemento(string nome, string utilizzo, string comando)
    {
        // aggiungo un pezzo alla coda (o inizializzo la testa)
        if(head == NULL)
        {
            head = new elemento();
            tail = head;
        }
        else
        {
            tail->next = new elemento();
            tail = tail ->next;
        }
        
        // inizializzo l'elemento
        tail->nome = nome;
        tail->utilizzo = utilizzo;
        tail->comando = comando;
    }

    void import(string filename)  
    {
        ifstream file(filename.c_str()); // a dire il vero basta filename

        string nome, utilizzo, comando;

        do
        {
            getline(file, nome);
            getline(file, utilizzo);
            getline(file, comando);

            pushElemento(nome, utilizzo, comando);
        } while(file.rdstate() == ios_base::goodbit); // non sono sicuro se funziona, prova...
    }
    
    void printList()
    {
        elemento *tmp = head;
        while(tmp != NULL)
        {
            cout << "nome: " << tmp->nome << "\n"
                 << "utilizzo: " << tmp->utilizzo << "\n"
                 << "comando: " << tmp->comando << "\n" << "\n";

            tmp = tmp->next;
        }
    }

    ~inventario()
    {
        // nota: il tuo inventario lasciava tutta la lista in memoria, qui non ci sono memory leaks.
        elemento *tmp;
        while((tmp = head) != NULL)
        {
            head = head->next;
            delete tmp;
        }
    }
};


int main()
{
    inventario inventario;

    inventario.import("database/inventario.txt");
    inventario.printList();
    
    return 0; 
}

BTW: nemmeno questo è testato, a dire il vero non avevo voglia di creare il file da importare xD però anche se c'è qualcosa da ritoccare il senso credo che si capisca.

Grazie St3ve, così com'è da segmentation fault, il problema è nella funzione import() dopo al salvataggio dei dati nel vector, ora vedo di aggiustarla se riesco!
Grazie mille! Non chiudo in caso arrivino ancora perle, non vorrei perdermele! :)

- - - Updated - - -
[MENTION=156155]St3ve[/MENTION]
Questo funziona... Mi sono sbattuto un pò ed in effetti fa quello che gli ho chiesto di fare...
Riguardo allo stile? Senza utilizzare costrutti non presenti nel codice, quindi senza aggiungerne di nuovi, l'algoritmo di per se ti gusta?

PHP:
#define intlin cout<<"-------------------------------------------------------------------------------"<<endl

#include<iostream>
#include<fstream>
#include<cstdlib>
#include<string>
#include<vector>
#define check cout<<"check raggiunto"<<endl; exit(1)
using namespace std;

struct strumento
{
  string nome;
  string comando;
  
  strumento *next;
};

class inventario
{
protected:
  strumento *head, *tail;
  vector<string> vettore;
  
public:
  void Import();
  void Print();
};

inline void inventario::Import()
{
  string linea;
  ifstream file("database/inventario.txt");
    
  vettore.push_back("inventario\0"); // vettore[0]
    
  while(getline(file, linea))
    vettore.push_back(linea);
  
  head=new strumento;
  tail=head;
 
  tail->nome=vettore[1];
  tail->comando=vettore[2];
  
  for(int i=3; i<vettore.size(); i+=2)
  {
    tail->next=new strumento;
    tail=tail->next;
    tail->nome=vettore[i];
    tail->comando=vettore[i+1];
  }
  
  tail->next=NULL;
  tail=head;  
}

inline void inventario::Print()
{
  int i=1;
  
  do  
  {
    intlin;
    intlin;
    cout<<"OGGETTO "<<i<<endl;
    cout<<"    nome: "<<tail->nome<<endl;
    cout<<"    comando: "<<tail->comando<<endl;
    tail=tail->next;
    i++;
  }
  while(tail!=NULL);
}

int main()
{
  inventario inventario;
  inventario.Import();
  inventario.Print();
 
 return 0; 
}
 
Si, è già un bel passo avanti rispetto al primo codice postato.
Crasha se il numero delle linee da cui è composto il file è dispari, dovrebbe bastare modificare il for con for(int i=3; i<vettore.size()-1; i+=2) per risolvere il problema.

Ti sei dimenticato ancora di fare il distruttore, prova crearti un file bello grosso (un migliaio di linee) e modifica il codice in questo modo:
Codice:
void callInventario()
{
  inventario inventario;
  inventario.Import();
}

int main()
{
    for(int i=0; i<50000; i++)
        callInventario();
    
    char p;
    cin>>p;
 
 return 0; 
}
Avvialo e tieni d'occhio il task manager, vedi quanti GB di ram ti fa fuori. Se gli metti un distruttore tipo quello che avevo postato sopra io non consumerà praticamente niente.
 
Si, è già un bel passo avanti rispetto al primo codice postato.
Crasha se il numero delle linee da cui è composto il file è dispari, dovrebbe bastare modificare il for con for(int i=3; i<vettore.size()-1; i+=2) per risolvere il problema.

Ti sei dimenticato ancora di fare il distruttore, prova crearti un file bello grosso (un migliaio di linee) e modifica il codice in questo modo:
Codice:
void callInventario()
{
  inventario inventario;
  inventario.Import();
}

int main()
{
    for(int i=0; i<50000; i++)
        callInventario();
    
    char p;
    cin>>p;
 
 return 0; 
}
Avvialo e tieni d'occhio il task manager, vedi quanti GB di ram ti fa fuori. Se gli metti un distruttore tipo quello che avevo postato sopra io non consumerà praticamente niente.
Cacchio, hai un occhio notevole! Grazie! Il fatto è che il file per costituzione non sarà mai più di 60-100 righe, fa parte di un progettino più complesso. Il distruttore comunque sarebbe da mettere anche solo per correttezza sintattica.
Il file non potrà mai avere linee dispari, sempre per costituzione! :)
Grazie mille St3ve!
Candidati alle europee! Ti voto! ;)
Saluti
 
[MENTION=156155]St3ve[/MENTION]
scusa se ti disturbo! Non voglio aprire un altro topic per questa piccolezza, e facendo parte dello stesso progetto del codice postato di sopra non è propriamente OT.
Ho fatto una piccola funzione di attesa che vorrei interporre fra il console-output di due char.
Cioè vorrei stampare 'a'
attendere secondi tot
stampare 'b' sulla stessa linea!
Il mio codice:
(la classe è molto vuota, è da riempire quindi non considerarla, così come le inclusioni di troppo! C'è una ragione per tutto che non sto qui a spiegare ;) grazie mille! )

PHP:
#include<iostream>
#include<string>
#include<cstdlib>
#include<ctime>
#define clear system("clear")
#define read system("read")
using namespace std;

void wait(double secondi)
{
time_t adesso, inizio;
inizio = adesso = time(NULL);

while(adesso<(inizio+secondi)) 
  adesso=time(NULL);
} 

class banner
{
public:
  void opening();
};

inline void banner::opening()
{ 
  cout<<'a';
  wait(0.5);  //problema! L'output è quello che ti aspetteresti da wait(0.5); cout<<"ab";
  cout<<'b'<<endl;
  
}

int main()
{
  banner banner;
  banner.opening();
  
 return 0; 
}

L'output di questo è:
attesa di mezzo secondo +
Codice:
ab
 
Aggiungi cout.flush(); dopo il primo cout.

Comunque per mettere in pausa il programma usa this_thread::sleep_for(chrono::milliseconds(500)); con g++ devi compilare con la flag --std=c++11 (devi anche mettere #include <thread>). In alternativa puoi usare Sleep (in windows.h) o usleep (in unistd.h).
 
  • Mi piace
Reazioni: Simur Birkoff
Aggiungi cout.flush(); dopo il primo cout.

Comunque per mettere in pausa il programma usa this_thread::sleep_for(chrono::milliseconds(500)); con g++ devi compilare con la flag --std=c++11 (devi anche mettere #include <thread>). In alternativa puoi usare Sleep (in windows.h) o usleep (in unistd.h).

Grazie! Rapido e preparatissimo come sempre!
Saluti!
 
Stato
Discussione chiusa ad ulteriori risposte.