Torna indietro   Hardware Upgrade Forum > Software > Programmazione

I nuovi schermi QD-OLED di quinta generazione di MSI, per i gamers
I nuovi schermi QD-OLED di quinta generazione di MSI, per i gamers
MSI continua ad investire nel proporre schermi pensati per rispondere alle esigenze dei videogiocatori, utilizzando la quinta generazione di tecnologia QD-OLED sviluppata da Samsung. Il modello MPG 341CQR QD-OLED X36 è lpultima novità al debutto in concomitanza con il CES 2026, uno schermo curvo di ampia risoluzione pensato per i videogiocatori più esigenti
Recensione vivo X300 Pro: è ancora lui il re della fotografia mobile, peccato per la batteria
Recensione vivo X300 Pro: è ancora lui il re della fotografia mobile, peccato per la batteria
vivo X300 Pro rappresenta un'evoluzione misurata della serie fotografica del produttore cinese, con un sistema di fotocamere migliorato, chipset Dimensity 9500 di ultima generazione e l'arrivo dell'interfaccia OriginOS 6 anche sui modelli internazionali. La scelta di limitare la batteria a 5.440mAh nel mercato europeo, rispetto ai 6.510mAh disponibili altrove, fa storcere un po' il naso
Lenovo Legion Go 2: Ryzen Z2 Extreme e OLED 8,8'' per spingere gli handheld gaming PC al massimo
Lenovo Legion Go 2: Ryzen Z2 Extreme e OLED 8,8'' per spingere gli handheld gaming PC al massimo
Lenovo Legion Go 2 è la nuova handheld PC gaming con processore AMD Ryzen Z2 Extreme (8 core Zen 5/5c, GPU RDNA 3.5 16 CU) e schermo OLED 8,8" 1920x1200 144Hz. È dotata anche di controller rimovibili TrueStrike con joystick Hall effect e una batteria da 74Wh. Rispetto al dispositivo che l'ha preceduta, migliora ergonomia e prestazioni a basse risoluzioni, ma pesa 920g e costa 1.299€ nella configurazione con 32GB RAM/1TB SSD e Z2 Extreme
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 18-02-2011, 21:17   #1
Duchamp
Member
 
L'Avatar di Duchamp
 
Iscritto dal: Apr 2010
Messaggi: 67
[C++] stack dinamico con i template

Buonasera a tutti.
Avendo bisogno di creare un array multidimensionale dinamico e volendo sperimentare con i template, ho deciso di cogliere questi due piccioni e ho steso qualcosa. Da quanto ho capito, posso poi dichiarare uno stack di stack in modo molto semplice, in altre parole l'array multidimensionale di cui sopra.

Codice:
template <class T> class gVector {
public:

  // proprietà
  uint32_t  size;
  T        *stack;
  
  // metodi
  void init() {
    size  = 0;
    stack = NULL;
  }

  void add(T &item) {
    stack = (T*) realloc(stack, (size+1)*sizeof(T));
    size += 1;
    stack[size-1] = item;
  }
    
  void clear() {
    if (stack != NULL) {
      free(stack);    
      stack = NULL;
      size = 0;
    }     
  }
  
  T at(uint32_t p) {
    return stack[p];
  }
};

Considerando che manca completamente la gestione degli errori e i metodi di cancellazione elementi, mi piacerebbe avere un parere da voi. Sono aperto ad ogni suggerimento/critica.
Non siate troppo cattivi
Duchamp è offline   Rispondi citando il messaggio o parte di esso
Old 19-02-2011, 00:50   #2
tomminno
Senior Member
 
Iscritto dal: Oct 2005
Messaggi: 3306
La prima critica da sollevare è che uno stack non è un array. Vuoi uno stack o un array?

Quella che hai fatto te sarebbe una "brutta copia", scusami il termine, della classe std::vector, oltre tutto la tua ha un sacco di problemi.
Il primo che mi viene in mente è: prova ad usare il tuo codice con una classe con un campo int e uno std::string, avrai delle spiacevolissime sorprese.
Realloc così come tutte le funzioni di allocazione del C non chiamano il costruttore della classe, ma lavorano a basso livello riservando un'area di memoria.
Quando il codice proverà a copiare la stringa di item sul tuo oggetto allocato con realloc si troverà a copiare i valori su un puntatore non inizializzato, perchè non è stato chiamato il costruttore della classe string.

Quando in C++ si arriva ad usare le funzioni di allocazione del C, secondo il mio parere, si sta sbagliando qualcosa.

Ma hai proprio la necessità di reimplementare funzionalità già presenti nella libreria standard? Vuoi un array dinamico? Usa std::vector. Vuoi uno stack dinamico? usa std::stack.
tomminno è offline   Rispondi citando il messaggio o parte di esso
Old 19-02-2011, 10:43   #3
Duchamp
Member
 
L'Avatar di Duchamp
 
Iscritto dal: Apr 2010
Messaggi: 67
Ciao tomminno, grazie degli spunti!
Allora, parto dal fondo: il mio è assolutamente un esercizio per capire l'uso dei template, non avrei il coraggio di introdurre codice del genere in un programma "serio"

Per lo stack vs. array... hai ragione, visto che fornisco il metodo at() direi che si tratta di array.

Per quanto riguarda realloc, comprendo la bassezza del mix C e C++ ma mi chiedo: dato che il mio template non ha costruttore e si affida a quello di default (che non fa nulla), dovrei comunque chiamare init() in ogni caso per inizializzare le proprietà; il problema sorge quando creo gVector di classi, il cui costruttore non verrebbe chiamato. Dico bene?

Ultima modifica di Duchamp : 19-02-2011 alle 10:45.
Duchamp è offline   Rispondi citando il messaggio o parte di esso
Old 19-02-2011, 11:03   #4
tomminno
Senior Member
 
Iscritto dal: Oct 2005
Messaggi: 3306
Quote:
Originariamente inviato da Duchamp Guarda i messaggi
Per quanto riguarda realloc, comprendo la bassezza del mix C e C++ ma mi chiedo: dato che il mio template non ha costruttore e si affida a quello di default (che non fa nulla), dovrei comunque chiamare init() in ogni caso per inizializzare le proprietà;
Il tuo init in realtà dovrebbe essere il costruttore di gVector.

Quote:
il problema sorge quando creo gVector di classi, il cui costruttore non verrebbe chiamato. Dico bene?
Si il problema nasce proprio in caso di utilizzo del tuo vettore con le classi le quali, senza la chiamata al costruttore, potrebbero risentirsene, specialmente se eseguono allocazioni dinamiche sul costruttore come per l'appunto std::string. E ovviamente no costruttore => no distruttore, che potrebbe essere anche peggio, in quanto potrebbero non essere liberate risorse magari non allocate sul costruttore.
tomminno è offline   Rispondi citando il messaggio o parte di esso
Old 19-02-2011, 17:56   #5
Duchamp
Member
 
L'Avatar di Duchamp
 
Iscritto dal: Apr 2010
Messaggi: 67
Quote:
Originariamente inviato da tomminno Guarda i messaggi
Si il problema nasce proprio in caso di utilizzo del tuo vettore con le classi le quali, senza la chiamata al costruttore, potrebbero risentirsene, specialmente se eseguono allocazioni dinamiche sul costruttore come per l'appunto std::string. E ovviamente no costruttore => no distruttore, che potrebbe essere anche peggio, in quanto potrebbero non essere liberate risorse magari non allocate sul costruttore.
Ora è tutto molto più chiaro!
Mediterò su queste informazioni, nel frattempo ti ringrazio molto.
Per ulteriori sviluppi riutilizzerò questo post.
Duchamp è offline   Rispondi citando il messaggio o parte di esso
Old 20-02-2011, 22:48   #6
Duchamp
Member
 
L'Avatar di Duchamp
 
Iscritto dal: Apr 2010
Messaggi: 67
Ritorno con gli sviluppi. Ho corretto il mio template come segue:

Codice:
template <class T> class gVector {
public:

  // proprietà
  uint32_t  size;
  T          *stack;
  
  // metodi
  gVector() : size(0), stack(NULL) {}
~gVector() { clear(); }

  void add(T &item) {
    T *tmp = new T[size+1];
    for (uint32_t i=0; i<size; i++)
      tmp[i] = stack[i];
    tmp[size] = item;
    delete [] stack;
    stack = tmp;
    size += 1;	
  }
    
  void clear() {
    if (size > 0) {
      delete [] stack;    
      stack = NULL;
      size = 0;
    }     
  }
  
  T at(uint32_t p) {
    return stack[p];
  }
};
Ho notato che questo sistema si comporta male quando si creano array di array, ad esempio:

Codice:
gVector< gVector<int> > mtx;
Quando, dopo aver riempito a dovere, provo ad accedere ad un elemento del sotto-array con

Codice:
mtx.at(x).at(y);
ottengo valori incoerenti con la realtà.
Sbaglio a pensare sia dovuto al copy constructor di default che copia "male" i valori di stack?

(ribadisco che il mio non è un voler reinventare la ruota, sto cercando di imparare i template e i dinamismi dei costruttori )

Grazie in anticipo!

Ultima modifica di Duchamp : 20-02-2011 alle 23:15.
Duchamp è offline   Rispondi citando il messaggio o parte di esso
Old 20-02-2011, 23:04   #7
Supdario
Member
 
Iscritto dal: Mar 2008
Messaggi: 267
1) Il tuo metodo per il ridimensionamento è giusto (anche se potresti copiare l'array in modo più efficiente usando la funzione "memcpy"), però si può capire facilmente che estendendo l'array solo di 1, il tutto diventa molto lento.
In questo caso i usano i cosiddetti chunks, cioè l'array non viene ridimensionato di 1, ma viene ridimensionato in abbondanza (tipo raddoppiando i blocchi o estendendoli di un numero fisso tipo 64), ed ogni volta che il vettore si riempie, viene allocata altra memoria in abbondanza.

2) Se ci hai fatto caso, nella prima chiamata alla funzione add il vettore "stack" non è ancora stato inizializzato (ovviamente), ma il delete [] viene richiamato ugualmente. Questo potrebbe dare risultati inaspettati, quindi ti consiglio di impostare il puntatore "stack" a NULL nel costruttore della classe.
Supdario è offline   Rispondi citando il messaggio o parte di esso
Old 20-02-2011, 23:14   #8
Duchamp
Member
 
L'Avatar di Duchamp
 
Iscritto dal: Apr 2010
Messaggi: 67
Ciao Supdario e grazie per le risposte.

Quote:
Originariamente inviato da Supdario Guarda i messaggi
1) Il tuo metodo per il ridimensionamento è giusto (anche se potresti copiare l'array in modo più efficiente usando la funzione "memcpy"), però si può capire facilmente che estendendo l'array solo di 1, il tutto diventa molto lento.
In questo caso i usano i cosiddetti chunks, cioè l'array non viene ridimensionato di 1, ma viene ridimensionato in abbondanza (tipo raddoppiando i blocchi o estendendoli di un numero fisso tipo 64), ed ogni volta che il vettore si riempie, viene allocata altra memoria in abbondanza.
Questa tecnica è molto interessante e l'avevo letta in merito ai meccanismi del "famoso" std::vector. Memcpy però non rischia di andare in conflitto con ciò che è stato allocato da new?


Quote:
Originariamente inviato da Supdario Guarda i messaggi
2) Se ci hai fatto caso, nella prima chiamata alla funzione add il vettore "stack" non è ancora stato inizializzato (ovviamente), ma il delete [] viene richiamato ugualmente. Questo potrebbe dare risultati inaspettati, quindi ti consiglio di impostare il puntatore "stack" a NULL nel costruttore della classe.
Mea culpa, ho cannato nel copia-incolla. Nel costruttore già imposto stack(NULL), ma nello snippet sopra compare s(NULL). Ho corretto
Duchamp è offline   Rispondi citando il messaggio o parte di esso
Old 20-02-2011, 23:43   #9
Supdario
Member
 
Iscritto dal: Mar 2008
Messaggi: 267
Quote:
Originariamente inviato da Duchamp Guarda i messaggi
Ciao Supdario e grazie per le risposte.
Questa tecnica è molto interessante e l'avevo letta in merito ai meccanismi del "famoso" std::vector. Memcpy però non rischia di andare in conflitto con ciò che è stato allocato da new?
Il problema che si poneva prima era quello di allocare la memoria, ed eseguendo realloc, non viene chiamato il costruttore della classe di cui vuoi allocare il vettore.

In questo caso, invece, si tratta semplicemente di eseguire la copia binaria di un vettore, cioè copiarlo esattamente com'è da una locazione di memoria ad un'altra. Per sicurezza, assicurati di usare std::memcpy (e non il memcpy del C), anche se ad occhio non dovrebbe cambiare niente.
Supdario è offline   Rispondi citando il messaggio o parte di esso
Old 22-02-2011, 09:55   #10
Duchamp
Member
 
L'Avatar di Duchamp
 
Iscritto dal: Apr 2010
Messaggi: 67
Quote:
Originariamente inviato da Supdario Guarda i messaggi
...
Davvero, c'è sempre da imparare, ero completamente all'oscuro del memcpy in std! Ah l'autodidattarianesimo...

Che ne pensi/pensate invece del problema della matrice, o gVector< gVector<...> >?
Duchamp è offline   Rispondi citando il messaggio o parte di esso
Old 22-02-2011, 16:04   #11
malocchio
Senior Member
 
L'Avatar di malocchio
 
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
Quel tuo gVector utilizza memoria dinamica... è consigliabile definire un costruttore di copia e un operatore di assegnamento e, se fanno le cose come si deve, l'ultimo problema dovrebbe sparire.
Cerca di capire tu perché.
__________________
malocchio è offline   Rispondi citando il messaggio o parte di esso
Old 22-02-2011, 22:44   #12
Duchamp
Member
 
L'Avatar di Duchamp
 
Iscritto dal: Apr 2010
Messaggi: 67
Quote:
Originariamente inviato da malocchio Guarda i messaggi
Quel tuo gVector utilizza memoria dinamica... è consigliabile definire un costruttore di copia e un operatore di assegnamento e, se fanno le cose come si deve, l'ultimo problema dovrebbe sparire.
Cerca di capire tu perché.
Grazie anche a te per la collaborazione!
Quello che io pensavo di implementare (pseudocodice):

Codice:
gVector (const gVector &other) {
  std::memcpy(...da other.stack a this.stack)
}
Anche se ho un dubbio concettuale: così facendo mi pare si crei e poi si distrugga (alloca e poi dealloca) un bel po' di roba, in casi tipo:

Codice:
mtx.at(x).at(y);
E' una situazione tipica e corretta per il c++?
Duchamp è offline   Rispondi citando il messaggio o parte di esso
Old 22-02-2011, 22:50   #13
malocchio
Senior Member
 
L'Avatar di malocchio
 
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
Quote:
Originariamente inviato da Duchamp Guarda i messaggi
Grazie anche a te per la collaborazione!
Quello che io pensavo di implementare (pseudocodice):

Codice:
gVector (const gVector &other) {
  std::memcpy(...da other.stack a this.stack)
}
Anche se ho un dubbio concettuale: così facendo mi pare si crei e poi si distrugga (alloca e poi dealloca) un bel po' di roba, in casi tipo:

Codice:
mtx.at(x).at(y);
E' una situazione tipica e corretta per il c++?
Esattamente: le allocazioni e deallocazioni sono molto numerose.
Corretto è corretto...
che poi faccia schifo per le performance (anche se con quantità di dati piccole la differenza potrebbe essere impercettibile) è tutto un altro paio di maniche
Sempre meglio di un segfault...

Vabbè, voglio sbilanciarmi: diciamo che potresti prendere in considerazione l'idea di modificare il metodo at() in modo che restituisca un reference...
__________________
malocchio è offline   Rispondi citando il messaggio o parte di esso
Old 22-02-2011, 23:37   #14
Duchamp
Member
 
L'Avatar di Duchamp
 
Iscritto dal: Apr 2010
Messaggi: 67
Quote:
Originariamente inviato da malocchio Guarda i messaggi
Sempre meglio di un segfault...
Non ci sono dubbi...

Quote:
Originariamente inviato da malocchio Guarda i messaggi
Vabbè, voglio sbilanciarmi: diciamo che potresti prendere in considerazione l'idea di modificare il metodo at() in modo che restituisca un reference...
Questa chicca permette di evitare la copia, un po' in stile "passing by reference"? In ogni caso adesso me la studio. Ti ringrazio ancora!
Duchamp è offline   Rispondi citando il messaggio o parte di esso
Old 22-02-2011, 23:44   #15
malocchio
Senior Member
 
L'Avatar di malocchio
 
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
Quote:
Originariamente inviato da Duchamp Guarda i messaggi
Questa chicca permette di evitare la copia, un po' in stile "passing by reference"? In ogni caso adesso me la studio. Ti ringrazio ancora!
Ehm sì... i reference si usano spesso per risparmiare sulle allocazioni "inutili". Attento che però è un'importante scelta di design della classe: prima di metterla giù in codice ci penserei due volte.
In ogni caso se la usi così:
Codice:
gVector< gVector<int> > gv;
...
...
gv.at(0).at(1);
dovrebbe funzionare e anche molto velocemente.
Occhio che però con i reference diventa possibile fare anche cose come
Codice:
gVector< gVector<int> > gv;
...
...
gv.at(0).at(1) = 1234567;
gv.at(0).at(1)++;
gv.at(1) = gv.at(2);
e altre porcate molto molto arrapanti.
__________________
malocchio è offline   Rispondi citando il messaggio o parte di esso
Old 23-02-2011, 09:12   #16
tomminno
Senior Member
 
Iscritto dal: Oct 2005
Messaggi: 3306
Quote:
Originariamente inviato da malocchio Guarda i messaggi
Occhio che però con i reference diventa possibile fare anche cose come
Codice:
gVector< gVector<int> > gv;
...
...
gv.at(0).at(1) = 1234567;
gv.at(0).at(1)++;
gv.at(1) = gv.at(2);
e altre porcate molto molto arrapanti.
Per questo esistono i const reference
Se per scelta i dati devono essere modificabili dall'esterno quelle non sono porcate ma funzionalità previste, altrimenti meglio usare i const reference e passa la paura.
tomminno è offline   Rispondi citando il messaggio o parte di esso
Old 23-02-2011, 13:18   #17
malocchio
Senior Member
 
L'Avatar di malocchio
 
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
Quote:
Originariamente inviato da tomminno Guarda i messaggi
Per questo esistono i const reference
Se per scelta i dati devono essere modificabili dall'esterno quelle non sono porcate ma funzionalità previste, altrimenti meglio usare i const reference e passa la paura.
Hai perfettamente ragione e mi sorprendo di non aver sollevato io l'argomento visto che sono un "amante" del const.

Però c'è da dire che il const funziona bene se messo in tutti i posti dove va messo, altrimenti perde un po' la sua comodità...
Volendo esser pignoli quindi andrebbe messo come attributo
Codice:
template <class T> class gVector {
public:

  // proprietà
  uint32_t  size;
  T          *stack;
  
  // metodi
  gVector() : size(0), stack(NULL) {}
~gVector() { clear(); }

  void add(T const& item) {
    T *tmp = new T[size+1];
    for (uint32_t i=0; i<size; i++)
      tmp[i] = stack[i];
    tmp[size] = item;
    delete [] stack;
    stack = tmp;
    size += 1;	
  }
    
  void clear() {
    if (size > 0) {
      delete [] stack;    
      stack = NULL;
      size = 0;
    }     
  }
  
  T const& at(const uint32_t p) const {
    return stack[p];
  }
};
ho usato la sintassi più moderna, che piace di più al mio occhio...
Per dubbi consiglio http://www.parashift.com/c++-faq-lit....html#faq-18.6, punti 18.6 e 18.8

non sono sicuro della correttezza dell'intestazione dell'ultimo metodo... bisognerebbe provare a compilarlo...
__________________
malocchio è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


I nuovi schermi QD-OLED di quinta generazione di MSI, per i gamers I nuovi schermi QD-OLED di quinta generazione di...
Recensione vivo X300 Pro: è ancora lui il re della fotografia mobile, peccato per la batteria Recensione vivo X300 Pro: è ancora lui il...
Lenovo Legion Go 2: Ryzen Z2 Extreme e OLED 8,8'' per spingere gli handheld gaming PC al massimo Lenovo Legion Go 2: Ryzen Z2 Extreme e OLED 8,8'...
AWS re:Invent 2025: inizia l'era dell'AI-as-a-Service con al centro gli agenti AWS re:Invent 2025: inizia l'era dell'AI-as-a-Se...
Cos'è la bolla dell'IA e perché se ne parla Cos'è la bolla dell'IA e perché se...
La Russia prosegue lo sviluppo di reatto...
Roscosmos: da quest'anno ci potrà...
Amazon, tutte le offerte e qualche novit...
Sedie gaming in offerta su Amazon: desig...
Scope elettriche in offerta Amazon: mode...
Ricarica EV fino a 22 kW spendendo poco:...
Costa solo 139€ ma fa tutto: Lefant M330...
Amazon Haul spinge sul risparmio: sconti...
Oral-B iO in offerta su Amazon: maxi sco...
I cosmonauti avrebbero riparato tutte le...
Artemis II: la NASA conferma il lancio d...
Il CEO di Embrak Studios difende l'uso d...
Il Trump Phone è sempre più un mistero: ...
OPPO ha svelato la serie Reno 15 "global...
Poste ID diventa a pagamento: l'identità...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 06:29.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Served by www3v