|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Member
Iscritto dal: Oct 2004
Città: Monza (MI)
Messaggi: 46
|
[c++] Valgrind rileva diversi errori di scrittura
Sto realizzando una classe che rappresenta una matrice templata. Ormai sono a buon punto, ma eseguendo valgrind mi accorgo che ci sono un pò di errori (nessun memory leak per ora). Provando il copy constructor ricevo i seguenti errori:
Invalid write of size 4 ==2410== at 0x4010C4: miamatrice<int>::miamatrice(miamatrice<int> const&) (in /media/Storage/Progetto c++/mymatrix2/a.out) ==2410== by 0x400CB6: main (in /media/Storage/Progetto c++/mymatrix2/a.out) ==2410== Address 0x59441f4 is 0 bytes after a block of size 4 alloc'd ==2410== at 0x4C2596C: operator new(unsigned long) (vg_replace_malloc.c:220) ==2410== by 0x40104C: miamatrice<int>::miamatrice(miamatrice<int> const&) (in /media/Storage/Progetto c++/mymatrix2/a.out) ==2410== by 0x400CB6: main (in /media/Storage/Progetto c++/mymatrix2/a.out) La classe è così definita: Codice:
miamatrice(const miamatrice &other) {
nr_=other.nr_;
nc_=other.nc_;
m_=new T*[nr_];
for (int righe=0; righe<nr_; ++righe)
{
m_[righe]=new T(nc_);
for (int colonne=0; colonne < nc_; ++colonne)
{
m_[righe][colonne]=other.m_[righe][colonne];
}
}
}
T** m_; unsigned int nr_; unsigned int nc_; e costruttore utilizzato per costruire la prima delle due matrici: Codice:
miamatrice(unsigned int nr, unsigned int nc){
nr_=nr;
nc_=nc;
m_=new T*[nr];
for (int i=0;i<nr;++i) m_[i]=new T[nc];
}
Di errori ne ho molti altri cominciare a risolvere questo sarebbe un buon inizio Ultima modifica di cionci : 08-02-2010 alle 20:41. |
|
|
|
|
|
#2 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
m_[righe]=new T(nc_);
forse m_[righe]=new T[nc_]; |
|
|
|
|
|
#3 |
|
Member
Iscritto dal: Oct 2004
Città: Monza (MI)
Messaggi: 46
|
è giusto, non so perchè vedendo dei vecchi esempi mi è venuto da mettere con le parentesi tonde. Sono incappato in un problema più misterioso però. Se creo una matrice specificando le dimensioni ma non la inizializzo e la stampo non stampa una matrice di tutti 0, ma alcuni 0 e alcuni numeri "casuali". La cosa strana è che se dopo questa matrice ne creo un'altra con lo stesso procedimento questa sarà di tutti 0. Il costruttore che accetta le lunghezze in ingresso l'ho messo nel post di prima, cosa posso aver sbagliato?
Grazie per l'aiuto |
|
|
|
|
|
#4 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
E' normale. L'allocazione non azzera i valori memoria.
Per la seconda volta, probabilmente la matrice viene allocata nella stessa posizione in cui prima c'erano tutti zero (magari proprio perché avevi inizializzato la matrice precedente con tutti zero). |
|
|
|
|
|
#5 | |
|
Member
Iscritto dal: Oct 2004
Città: Monza (MI)
Messaggi: 46
|
Quote:
Ho definito l'operatore ++ , e provando a ciclarlo nel main effettivamente stampa tutti i valori correttamente, ma dopo aver beccato l'ultimo elemento valgrind mi rivela un errore di invalid read! Non credo che il for nel main vada oltre la dimensione della matrice, infatti se lo ciclo una volta di meno mi stampa tutti gli elementi tranne uno e non dà nessun errore questa è la funzione di incremento dell' operatore: iterator operator++(int) { iterator(*this); if (act_c >= colonne-1){ act_c=0; act_r++; ptr=&(supporto[act_r][act_c]); } else { if (act_r < righe){ act_c++; ptr=&(supporto[act_r][act_c]); } } return *this; } e questo è il ciclo nel main che si occupa di stamparlo: for(int i=0; i<A.getRows()* A.getColumns(); i++){ cout<<*ita<<endl; ++ita; } cosa può generare questo invalid read? Comunque grazie mille per le dritte, sono state di grande aiuto |
|
|
|
|
|
|
#6 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
f (act_c >= colonne){
O più semplicemente: counter++; ptr=&(supporto[counter / righe][counter % colonne]; |
|
|
|
|
|
#7 | |
|
Member
Iscritto dal: Oct 2004
Città: Monza (MI)
Messaggi: 46
|
Quote:
fare invece act_c>=colonne non va bene perchè se le colonne sono 6 act_c deve andare da 0 a 5.
|
|
|
|
|
|
|
#8 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Se rimangono allora il problema è altrove, prova a fare un po' di debugging condizionale
|
|
|
|
|
|
#9 |
|
Member
Iscritto dal: Oct 2004
Città: Monza (MI)
Messaggi: 46
|
|
|
|
|
|
|
#10 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
|
|
|
|
|
|
#11 |
|
Member
Iscritto dal: Oct 2004
Città: Monza (MI)
Messaggi: 46
|
|
|
|
|
|
|
#12 |
|
Member
Iscritto dal: Oct 2004
Città: Monza (MI)
Messaggi: 46
|
Allora, sto affrontando l'end dell'iteratore. Ho capito che devo puntare fuori dalla matrice per esempio il primo elemento (quindi prima colonna) di una riga oltre la matrice.
iterator end() { T* ptr; return ptr; } il problema è che non so che tipo di valore ritornare nel metodo end, perchè dando un'occhiata ad alcuni testi mi era sembrato che fosse possibile ritornare un puntatore al dato ma non ci sono riuscito. Considerando che il mio begin è questo: iterator begin() { return iterator(m_,nr_ , nc_); } ovvero il begin chiama il costruttore di iterator e gli dice di creare una matrice con nr_ righe e nc_colonne. Non potrei fare lo stesso nel metodo end, perchè quello è un costruttore che crea un nuovo iteratore che punta alla prima cella della matrice. Cosa posso fare allora? |
|
|
|
|
|
#13 |
|
Member
Iscritto dal: Oct 2004
Città: Monza (MI)
Messaggi: 46
|
come non detto dovrei aver fatto l'end dell'iterator. Mi sembra che l'end funzioni bene poichè se faccio un for o un while il ciclo termina correttamente però chiamare l'end genera un invalid read. Ecco come ho definito l'end:
iterator end() { return iterator(m_,nr_,nc_,nr_,0); } in questo modo l'end chiama il costruttore che crea un iterator che punta una riga dopo l'ultima riga della matrice e alla cella zero. ecco il costruttore: iterator(T** mat, unsigned int rows, unsigned int cols, unsigned int it_rows, unsigned int it_cols){ righe=rows; colonne=cols; act_r=it_rows; act_c=it_cols; supporto=mat; ptr=&mat[act_r][act_c]; } cosa c'è di sbagliato? |
|
|
|
|
|
#14 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
ptr=&mat[act_r][act_c];
Devi accedere alla matrice solo nel momento in cui usi l'operatore * o ->, ptr te lo devi calcolare solo in quel momento. |
|
|
|
|
|
#15 | |
|
Member
Iscritto dal: Oct 2004
Città: Monza (MI)
Messaggi: 46
|
Quote:
Questo perchè matrice.end non va ad aggiornare il puntatore, visto che l'assegnamento è rimasto solo negli operatori sopra citati |
|
|
|
|
|
|
#16 | |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Quote:
Come nell'esempio che ti ho fatto prima...usa solamente un contatore. end() semplicemente lo inizializzerà a righe*colonne. |
|
|
|
|
|
|
#17 |
|
Member
Iscritto dal: Oct 2004
Città: Monza (MI)
Messaggi: 46
|
stai dicendo che nell'operatore di confronto invece che confrontare i puntatori devo confrontare solo gli indici? in questo modo se due iteratori diversi puntano a matrici diverse ma sono casualmente allo stesso numero di righe e colonne l'operatore di uguaglianza ci casca
|
|
|
|
|
|
#18 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Questo lo puoi evitare andando a confrontare l'indirizzo di matrice[0][0].
|
|
|
|
|
|
#19 |
|
Member
Iscritto dal: Oct 2004
Città: Monza (MI)
Messaggi: 46
|
Grazie ai tuoi preziosi consigli dovrei aver risolto l'iteratore. Stavo cominciando a vedere un pò di eccezioni e per prima cosa ho pensato di gestire le eccezioni che possono scaturire dal copy constructor. L'ho definita così:
miamatrice(const miamatrice &other) { nr_=other.getRows(); nc_=other.nc_; m_=new T*[nr_]; int protettore; try{ protettore=0; for (int righe=0; righe<nr_; ++righe) { m_[righe]=new T[nc_]; protettore++; for (int colonne=0; colonne < nc_; ++colonne) { m_[righe][colonne]=other.m_[righe][colonne]; } } } catch (std::exception& e) { for(int i=0; i<=protettore; i++) delete[] m_[i]; throw; } } Il problema è che oltre a non sapere se così va bene non so neanche come testarlo. Come posso creare un test che lanci un eccezione dal costruttore di copia? |
|
|
|
|
|
#20 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
L'unica eccezione che può venire fuori lì è quella nella new:
std::bad_alloc Secondo me è una di quelle eccezioni che puoi lasciare ingestita o al limite controllarla a livelli più alti. Questo perché è talmente grave che pregiudica l'operatività sia del programma, ma anche solitamente del sistema. Quindi il tuo programma termina comunque. Certo sarebbe bene correre ai ripari, ma come fai senza poter allocare nuova memoria ? |
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 14:40.




















