|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Member
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 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 |
|
|
|
|
|
#2 |
|
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. |
|
|
|
|
|
#3 |
|
Member
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. |
|
|
|
|
|
#4 | ||
|
Senior Member
Iscritto dal: Oct 2005
Messaggi: 3306
|
Quote:
Quote:
|
||
|
|
|
|
|
#5 | |
|
Member
Iscritto dal: Apr 2010
Messaggi: 67
|
Quote:
Mediterò su queste informazioni, nel frattempo ti ringrazio molto. Per ulteriori sviluppi riutilizzerò questo post. |
|
|
|
|
|
|
#6 |
|
Member
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];
}
};
Codice:
gVector< gVector<int> > mtx; Codice:
mtx.at(x).at(y); 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. |
|
|
|
|
|
#7 |
|
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. |
|
|
|
|
|
#8 | ||
|
Member
Iscritto dal: Apr 2010
Messaggi: 67
|
Ciao Supdario e grazie per le risposte.
Quote:
Quote:
|
||
|
|
|
|
|
#9 | |
|
Member
Iscritto dal: Mar 2008
Messaggi: 267
|
Quote:
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. |
|
|
|
|
|
|
#10 |
|
Member
Iscritto dal: Apr 2010
Messaggi: 67
|
|
|
|
|
|
|
#11 |
|
Senior Member
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
Cerca di capire tu perché.
__________________
|
|
|
|
|
|
#12 | |
|
Member
Iscritto dal: Apr 2010
Messaggi: 67
|
Quote:
Quello che io pensavo di implementare (pseudocodice): Codice:
gVector (const gVector &other) {
std::memcpy(...da other.stack a this.stack)
}
Codice:
mtx.at(x).at(y); |
|
|
|
|
|
|
#13 | |
|
Senior Member
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
|
Quote:
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...
__________________
|
|
|
|
|
|
|
#14 |
|
Member
Iscritto dal: Apr 2010
Messaggi: 67
|
Non ci sono dubbi...
Questa chicca permette di evitare la copia, un po' in stile "passing by reference"? In ogni caso adesso me la studio. Ti ringrazio ancora! |
|
|
|
|
|
#15 | |
|
Senior Member
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
|
Quote:
In ogni caso se la usi così: Codice:
gVector< gVector<int> > gv; ... ... gv.at(0).at(1); 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);
__________________
|
|
|
|
|
|
|
#16 | |
|
Senior Member
Iscritto dal: Oct 2005
Messaggi: 3306
|
Quote:
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. |
|
|
|
|
|
|
#17 | |
|
Senior Member
Iscritto dal: Feb 2007
Città: Verona
Messaggi: 1060
|
Quote:
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];
}
};
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...
__________________
|
|
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 06:29.




















