PDA

Visualizza la versione completa : [C++] Polimorfismo e messaggio di errore "Invalid pointer"


adrycast
17-02-2011, 10:54
Buongiorno a tutti.
Ragazzi ho fatto un programma dove utilizzo sia il polimorfismo che la derivazione multipla. Il programma svolge il suo compito ma non so perch dopo l'esecuzione mostra i seguenti messaggi nel terminale scritti in rosso (programmo sotto Ubuntu con Eclipse):



*** glibc detected *** /home/adrycast/workspace/animali_derivazione/Debug/animali_derivazione: free(): invalid pointer: 0xbfc5b604 ***
======= Backtrace: =========
/lib/libc.so.6(+0x6c501)[0x17c501]
/lib/libc.so.6(+0x6dd70)[0x17dd70]
/lib/libc.so.6(cfree+0x6d)[0x180e5d]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0x3a5441]
/home/adrycast/workspace/animali_derivazione/Debug/animali_derivazione[0x8048f18]
/home/adrycast/workspace/animali_derivazione/Debug/animali_derivazione[0x80494ef]
/lib/libc.so.6(__libc_start_main+0xe7)[0x126ce7]
/home/adrycast/workspace/animali_derivazione/Debug/animali_derivazione[0x8048881]
======= Memory map: ========
00110000-00267000 r-xp 00000000 08:02 253474 /lib/libc-2.12.1.so
00267000-00269000 r--p 00157000 08:02 253474 /lib/libc-2.12.1.so
00269000-0026a000 rw-p 00159000 08:02 253474 /lib/libc-2.12.1.so
0026a000-0026d000 rw-p 00000000 00:00 0
002fb000-003da000 r-xp 00000000 08:02 656528 /usr/lib/libstdc++.so.6.0.14
003da000-003de000 r--p 000de000 08:02 656528 /usr/lib/libstdc++.so.6.0.14
003de000-003df000 rw-p 000e2000 08:02 656528 /usr/lib/libstdc++.so.6.0.14
003df000-003e6000 rw-p 00000000 00:00 0
005ee000-00612000 r-xp 00000000 08:02 253478 /lib/libm-2.12.1.so
00612000-00613000 r--p 00023000 08:02 253478 /lib/libm-2.12.1.so
00613000-00614000 rw-p 00024000 08:02 253478 /lib/libm-2.12.1.so
00ca6000-00cc2000 r-xp 00000000 08:02 253471 /lib/ld-2.12.1.so
00cc2000-00cc3000 r--p 0001b000 08:02 253471 /lib/ld-2.12.1.so
00cc3000-00cc4000 rw-p 0001c000 08:02 253471 /lib/ld-2.12.1.so
00eac000-00ec6000 r-xp 00000000 08:02 1316415 /lib/libgcc_s.so.1
00ec6000-00ec7000 r--p 00019000 08:02 1316415 /lib/libgcc_s.so.1
00ec7000-00ec8000 rw-p 0001a000 08:02 1316415 /lib/libgcc_s.so.1
00f1f000-00f20000 r-xp 00000000 00:00 0 [vdso]
08048000-0804b000 r-xp 00000000 08:02 1613514 /home/adrycast/workspace/animali_derivazione/Debug/animali_derivazione
0804b000-0804c000 r--p 00002000 08:02 1613514 /home/adrycast/workspace/animali_derivazione/Debug/animali_derivazione
0804c000-0804d000 rw-p 00003000 08:02 1613514 /home/adrycast/workspace/animali_derivazione/Debug/animali_derivazione
08bf2000-08c13000 rw-p 00000000 00:00 0 [heap]
b7600000-b7621000 rw-p 00000000 00:00 0
b7621000-b7700000 ---p 00000000 00:00 0
b77f3000-b77f6000 rw-p 00000000 00:00 0
b780c000-b7810000 rw-p 00000000 00:00 0
bfc3b000-bfc5c000 rw-p 00000000 00:00 0 [stack]



Suppongo che dipenda da qualche problema con l'allocazione dinamica (leggo heap e stack) ma se cosi fosse il compilatore non mi direbbe nulla nel momento in cui "alloco male" un puntatore?
Ovviamente non pretendo che vi mettiate a vedere tutto per filo e per segno ma magari siete gi incappati in una situazione simile e potete indicarmi dove ho sbagliato.

UN GRAZIE ANTICIPATO A CHI RISPONDE :)

PS
Qualcuno saprebbe spiegarmi anche come mai ogni volta che acquisisco una stringa utilizzando prima cin.ignore e poi cin.get finisce sempre per mangiarsi la prima lettera? Ad esempio inserisco PLUTO e lui legge LUTO... :dh:

PPS
Non so se poi utile, comunque allego anche l'output del programma e le varie sezioni di codice (non badate alla logica del programma, era solo per esercitarmi :D )


classe Animali (la classe base)


/*
* animali.h
*
* Created on: 16/feb/2011
* Author: adrycast
*/

#ifndef ANIMALI_H_
#define ANIMALI_H_

#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;

typedef char * stringa;

class Animali {

stringa nome;
float eta;

public:
//costruttori
Animali(){nome=NULL;}
Animali (const float & e) {eta=e;}
Animali (const char N[]);
Animali(const char N[], const float & e );

//funzioni polimorfe per le derivate
virtual void verso (){}
virtual void cibo(){}
virtual void ChiSono() {}

//funzioni per et
void setEta(){cout << "\nInserire eta': "; cin >> eta;}
float getEta() {return eta;}

//funzioni per nome
void setNome(){char n[15];cout<<"\nInserire nome: "; cin.ignore(); cin.get(n,14); nome=new char[strlen(n)+1];
strcpy(nome,n);}

stringa getNome(){return nome;}

//distruttore
virtual ~Animali() {delete nome;}
};

#endif /* ANIMALI_H_ */


/*
* animali.cpp
*
* Created on: 16/feb/2011
* Author: adrycast
*/

#include "animali.h"

Animali::Animali (const char N[]){

nome=new char[strlen(N)+1];
strcpy(nome,N);

}

Animali::Animali(const char N[], const float & e ){

nome=new char[strlen(N)+1];
strcpy(nome,N);

eta=e;

}

classe Cane (derivata di Animali)

/*
* cane.h
*
* Created on: 16/feb/2011
* Author: adrycast
*/

#ifndef CANE_H_
#define CANE_H_

#include "animali.h"

class Cane: public virtual Animali {

stringa pelo;
stringa razza;

public:
//Costruttori
Cane (const char N[],const float & eta, const char P[], const char R[]);
Cane (const char N[],const float & eta): Animali::Animali(N,eta) {}
Cane (const char P[]): Animali::Animali() { pelo=new char [strlen(P)+1]; strcpy(pelo,P);}

//ridefinizione delle funzioni virtuali
virtual void verso() {cout << "\nBAU! BAU!";}
virtual void cibo () {cout << "\nMangio di tutto!";}
virtual void ChiSono() {cout << "\nSono un cane!";}

//funzioni per pelo
void setPelo() {char Pelo[10]; cout<< "\nPelo: "; cin.ignore(); cin.get(Pelo, 9); pelo= new char [strlen(Pelo)+1];
strcpy(pelo, Pelo);}

stringa getPelo() {return pelo;}

//funzioni per razza
void setRazza();
stringa getRazza() {return razza;}

//distruttore
virtual ~Cane(){ delete pelo; delete razza;}



};


#endif /* CANE_H_ */



/*
* cane.cpp
*
* Created on: 16/feb/2011
* Author: adrycast
*/

#include "cane.h"

Cane::Cane (const char N[],const float & eta, const char P[], const char R[]): Animali::Animali(N,eta) {


razza= new char [strlen(R)+1];
strcpy(razza, R);

pelo= new char [strlen(P)+1];
strcpy(pelo, P);
}


void Cane::setRazza(){

char R[15];
cout << "\nRazza:";
cin.ignore();
cin.get(R,14);

razza= new char [strlen(R)+1];
strcpy(razza, R);

}



classe Lupo (altra derivata da Animali)



/*
* lupo.h
*
* Created on: 16/feb/2011
* Author: adrycast
*/

#ifndef LUPO_H_
#define LUPO_H_

#include "animali.h"

class Lupo: public virtual Animali {

public:
Lupo(const char N[], const float & e):Animali::Animali(N,e) {}

virtual void verso() {cout << "\nGRR! GRR!";}
virtual void cibo() {cout<<"\nPrediligo la carne fresca!";}
virtual void ChiSono() {cout << "\nSono un lupo!";}

virtual ~Lupo(){}

};


#endif /* LUPO_H_ */




classe CaneLupo (derivata da Cane e Lupo)



/*
* canelupo.h
*
* Created on: 16/feb/2011
* Author: adrycast
*/

#ifndef CANELUPO_H_
#define CANELUPO_H_

#include "animali.h"
#include "cane.h"
#include "lupo.h"

class CaneLupo: public Cane, public Lupo {

public:

CaneLupo (const char N[], const float & e): Cane::Cane(N,e), Lupo::Lupo(N,e){}

virtual void verso() {Cane::verso(); Lupo::verso();}
virtual void cibo() {Cane::cibo(); cout<<"\n ed inoltre"; Lupo::cibo();}
virtual void ChiSono() {Cane::ChiSono(); cout << "\n ed inoltre"; Lupo::ChiSono();}

virtual ~CaneLupo() {}
};

#endif /* CANELUPO_H_ */


MAIN

/*
* main.cpp
*
* Created on: 16/feb/2011
* Author: adrycast
*/

#include "animali.h"
#include "cane.h"
#include "lupo.h"
#include "canelupo.h"

int main () {

char N[20];
float e;

//azioni preliminari (per i costruttori)
cout << "\nNome animale: ";
cin.ignore();
cin.get(N, 19);
cout << "\Eta' animale: ";
cin >> e;

//inizializzo Classi
Animali a(N,e);
Cane c(N,e);
Lupo l(N,e);
CaneLupo cl(N,e);

cout << "\n****INIZIO****\n";
cout << "\n**CHIAMATE NORMALI!";

//su Animali
cout << "\neta' animale: "<<a.getEta();
cout << "\nnome animale: "<<a.getNome();
cout << "\n";

cout << "\nRICHIAMO CANE";
//su Cane
c.ChiSono();
c.setPelo();
cout << "\nHai scritto che il mio pelo "<<c.getPelo();
cout << "\n";
c.setRazza();
cout << "\nHai scritto che appartengo alla razza dei "<<c.getRazza();
cout << "\n";
cout << "\nIl mio verso ";
c.verso();
cout << " ed inolte ";
c.cibo();
cout << "\n";

cout << "\nRICHIAMO LUPO";
//su Lupo
l.ChiSono();
cout << "\n";
cout << "\nIl mio verso ";
l.verso();
cout << " ed inolte ";
l.cibo();
cout << "\n";

cout << "\nRICHIAMO CANELUPO";
//su CaneLupo
cl.ChiSono();
cout << "\n";
cout << "\nIl mio verso ";
cl.verso();
cout << " ed inolte ";
cl.cibo();

cout << "\n****FINE PROG NORMALE****\n";
cout << "\n****INIZIO PROG CON PUNTATORI E BINDING DINAMICO****\n";

typedef Animali * A;

cout << "\n**Punto CANE da ANIMALI**";
A ptrc=&c;
ptrc->ChiSono();
cout << "\n";
ptrc->verso();
cout << "\n";
ptrc->cibo();
cout << "\n";

cout << "\n**Punto LUPO da ANIMALI**";
A ptrl=&l;
ptrl->ChiSono();
cout << "\n";
ptrl->verso();
cout << "\n";
ptrl->cibo();
cout << "\n";

cout << "\n**Punto CANELUPO da CANE**";
typedef Cane * C;
C ptrcl=&cl;
ptrcl->ChiSono();
cout << "\n";
ptrcl->verso();
cout << "\n";
ptrcl->cibo();
cout << "\n";


delete ptrc;
delete ptrl;
delete ptrcl;

a.~Animali();
c.~Cane();
l.~Lupo();
cl.~CaneLupo();

cout << "\n**********FINE**********\n";

return EXIT_SUCCESS;

}

Qui poi chiamo o non chiamo i distruttori e dealloco o non dealloco i puntatori al prog non fa nessuna differenza, ho sempre l'output di errore dal terminale.


OUTPUT

Nome animale: PLUTO
ta' animale: 8

****INIZIO****

**CHIAMATE NORMALI!
eta' animale: 8
nome animale: LUTO

RICHIAMO CANE
Sono un cane!
Pelo: corto

Hai scritto che il mio pelo corto

Razza:labrador

Hai scritto che appartengo alla razza dei labrador

Il mio verso
BAU! BAU! ed inolte
Mangio di tutto!

RICHIAMO LUPO
Sono un lupo!

Il mio verso
GRR! GRR! ed inolte
Prediligo la carne fresca!

RICHIAMO CANELUPO
Sono un cane!
ed inoltre
Sono un lupo!

Il mio verso
BAU! BAU!
GRR! GRR! ed inolte
Mangio di tutto!
ed inoltre
Prediligo la carne fresca!
****FINE PROG NORMALE****

****INIZIO PROG CON PUNTATORI E BINDING DINAMICO****

**Punto CANE da ANIMALI**
Sono un cane!

BAU! BAU!

Mangio di tutto!

**Punto LUPO da ANIMALI**
Sono un lupo!

GRR! GRR!

Prediligo la carne fresca!

**Punto CANELUPO da CANE**
Sono un cane!
ed inoltre
Sono un lupo!

BAU! BAU!
GRR! GRR!

Mangio di tutto!
ed inoltre
Prediligo la carne fresca!
Ovviamente seguito dall'errore scritto sopra.

lolide
17-02-2011, 11:31
L'errore dice

*** glibc detected *** /home/adrycast/workspace/animali_derivazione/Debug/animali_derivazione: free(): invalid pointer: 0xbfc5b604 ***

Gia ti dovrebbe far pensare che non che alloca male la memoria, ma la libera male, ed il perch evidente:

Perch chiami esplicitamente il distruttore ?
Viene fatto implicitamente quando viene distrutto l'oggetto. Il problema che crei degli oggetti sullo stack e poi li fai puntare da un reference.

Fai delete sulle reference quindi il compilatore (non tutti) non vedono un errore, ma sbagliato: prima li distruggi con delete, ma poi vengono distrutti a loro volta perch sono statici, quindi di fatto richiami 2 volte i distruttori.

Togli i delete e le chiamate ai distruttori perch non servono. La memoria di quegli oggetti viene liberata perch sono statici.

PS: per il problema di cin prova a fare cin.flush prima di get

adrycast
17-02-2011, 11:49
Originariamente inviato da lolide
L'errore dice

*** glibc detected *** /home/adrycast/workspace/animali_derivazione/Debug/animali_derivazione: free(): invalid pointer: 0xbfc5b604 ***

Gia ti dovrebbe far pensare che non che alloca male la memoria, ma la libera male, ed il perch evidente:

Perch chiami esplicitamente il distruttore ?
Viene fatto implicitamente quando viene distrutto l'oggetto. Il problema che crei degli oggetti sullo stack e poi li fai puntare da un reference.

Fai delete sulle reference quindi il compilatore (non tutti) non vedono un errore, ma sbagliato: prima li distruggi con delete, ma poi vengono distrutti a loro volta perch sono statici, quindi di fatto richiami 2 volte i distruttori.

Togli i delete e le chiamate ai distruttori perch non servono. La memoria di quegli oggetti viene liberata perch sono statici.

PS: per il problema di cin prova a fare cin.flush prima di get

Ciao
grazie per la risposta (anche perch forse ho scritto un post un p troppo corposo :D )

Purtroppo non quello il problema.
Infatti di solito non richiamo mai i distruttori, un aggiunta che ho fatto in seguito alla prima esecuzione dove mi dava sempre gli stessi messaggi in output. Preso dall'idea della memoria ho pensato che per qualche strana ragione non mi deallocava bene gli spazi e cosi ho esplicitato le chiamate ma con o senza la "deallocazione esplicita" non mi cambia praticamente nulla :dh: :dh:

lolide
17-02-2011, 11:53
Originariamente inviato da adrycast
Ciao
grazie per la risposta (anche perch forse ho scritto un post un p troppo corposo :D )

Purtroppo non quello il problema.
Infatti di solito non richiamo mai i distruttori, un aggiunta che ho fatto in seguito alla prima esecuzione dove mi dava sempre gli stessi messaggi in output. Preso dall'idea della memoria ho pensato che per qualche strana ragione non mi deallocava bene gli spazi e cosi ho esplicitato le chiamate ma con o senza la "deallocazione esplicita" non mi cambia praticamente nulla :dh: :dh:

Hai tolto anche i delete ?

Questa parte:



delete ptrc;
delete ptrl;
delete ptrcl;

a.~Animali();
c.~Cane();
l.~Lupo();
cl.~CaneLupo();


deve sparire ;)

:ciauz:

adrycast
17-02-2011, 12:02
Originariamente inviato da lolide
Hai tolto anche i delete ?

Questa parte:



delete ptrc;
delete ptrl;
delete ptrcl;

a.~Animali();
c.~Cane();
l.~Lupo();
cl.~CaneLupo();


deve sparire ;)

:ciauz:

No ma questa parte non c'era proprio all'inizio e l'ho introdotta proprio come "possibile soluzione" al problema ma non era proprio scritta ad una prima stesura del codice. Il programma stato avviato sia CON che SENZA queste istruzioni e l'errore rimaneva lo stesso :dh: :dh:

lolide
17-02-2011, 12:17
Uhm.. sicuramente un problema di disallocazione.
Prova a fare un controllo se il puntatore dell'attributo che disallochi non sia 0, in ogni distruttore di ogni classe.

Dovresti risolvere, ma si dovrebbe ancora capire qual' il problema.
Comunque se risolvi, il problema che uno di quegli attributi non viene inizializzato, e quindi quando cerca di distruggerlo da errore.

adrycast
17-02-2011, 12:32
Originariamente inviato da lolide
Uhm.. sicuramente un problema di disallocazione.
Prova a fare un controllo se il puntatore dell'attributo che disallochi non sia 0, in ogni distruttore di ogni classe.

Dovresti risolvere, ma si dovrebbe ancora capire qual' il problema.
Comunque se risolvi, il problema che uno di quegli attributi non viene inizializzato, e quindi quando cerca di distruggerlo da errore.

Quindi dovrei mettere un controllo all'interno dei distruttori dici?
Per sarebbe parecchio strano (o almeno a me mi flipperebbe un p il cervello :D) ...nel senso che l'esecuzione fa tutto come deve, sia la parte in cui utilizzo il binding statico che la parte in cui faccio il binding dinamico con in puntatori, se i puntatori agli oggetti non fossero inizializzati l'esecuzione da un punto di vista logico non ne risentirebbe?

Comunque appena torno a casa (sto scendendo ora) provo a fare come hai detto e poi posto i risultati.

Ti ringrazio molto per l'aiuto :ciauz:

lolide
17-02-2011, 12:50
Originariamente inviato da adrycast
Quindi dovrei mettere un controllo all'interno dei distruttori dici?
Per sarebbe parecchio strano (o almeno a me mi flipperebbe un p il cervello :D) ...nel senso che l'esecuzione fa tutto come deve, sia la parte in cui utilizzo il binding statico che la parte in cui faccio il binding dinamico con in puntatori, se i puntatori agli oggetti non fossero inizializzati l'esecuzione da un punto di vista logico non ne risentirebbe?

Comunque appena torno a casa (sto scendendo ora) provo a fare come hai detto e poi posto i risultati.

Ti ringrazio molto per l'aiuto :ciauz:

Si hai ragione.
Infatti solo una prova: almeno sappiamo che qualche attributo della classe non viene allocato.

Ho letto il codice e mi sembra apposto, anch'io non mi spiego quell'errore.
Pu anche darsi che non so quando allochi gli attributi, magari c' qualche errore di memoria e non l'alloca.
Cominciamo a scartare le possibilit :)

PS: prova a correggere quel fatto di cin, magari proprio quello. aggiungi cin.flush prima di get.

shodan
17-02-2011, 14:03
A parte le 3000 allocazioni inutili che fai, uno dei problemi qui:


//distruttore
virtual ~Animali() {delete nome;}

nome un puntatore a una serie di char, non a un singolo char.
La sintassi corretta :


//distruttore
virtual ~Animali() {delete[] nome;}

adrycast
17-02-2011, 19:44
Grazie per le risposte e per lo sbattone di leggervi i vari pezzi di codice ragazzi :)

@shodan
Guarda le 3000 allocazioni sono per esercizio, come ad esempio 4 costruttori fatti per la classe Animali e poi ne uso sempre solo uno. Semplicemente ho un esame e faccio 10000 cose futili ai fini logici ma utili per farmi prendere la mano ad allocare e deallocare (ed infatti dealloco praticamente tutto..)

Comunque il problema non neanche quello che dici tu. Ho messo le parentesi quadre sia nel distruttore da te evidenziato che negli altri distruttori che dovevano deallocare stringhe ma il problema resta lo stesso.

@Iolide
Come avevamo previsto il controllo sulle deallocazioni dei distruttori non d problemi. Anche qui resta sempre il messaggio di invalid pointer..


:dh: :dh: :dh:

Loading