PDA

View Full Version : [C++] Malloc() & Spazio di allocazione


IceCoder
09-12-2007, 09:07
Ho un problema con malloc():

sto lavorando ad un progetto di grafica tridimensionale e devo caricare un modello 3D.
uso questa struttura:


#pragma pack(1)
typedef struct TAGcobHEADER
{
char Ident[3];
int nMeshes;
int nMaterials;
int FirstFrame;
int LastFrame;
int TicksPerFrame;
int FrameSpeed;
} cobHEADER;

typedef struct TAGcobVECTOR
{
float x;
float y;
float z;
} cobVECTOR;

typedef struct TAGcobMATERIAL
{
float ambR, ambG, ambB;
float diffR, diffG, diffB;
float specR, specG, specB;
float shine;
char tex[64];

} cobMATERIAL;
typedef struct TAGcobMESH
{
int nVertices;
int nFaces;
float posX, posY, posZ;
float rotX, rotY, rotZ;
float scalX, scalY, scalZ;
int useMaterial; //int as bool
int MatID;
cobVECTOR *VertexList;
int *FaceList;
} cobMESH;

#pragma pack()

class cobFILE
{
public:
cobHEADER Header;
cobMESH *MeshList;
cobMATERIAL *MaterialList;
int LoadModel(char *fname);
cobFILE();
cobFILE(char *fname);
~cobFILE();

};


Quando devo caricare la mesh in *MeshList creo un array di mesh ed in seguito per ogni mesh creo un array di vettori ed uno di 'int' per le facce.

Il problema è che dopo un totale di spazio allocato con malloc() ho un crash alla prima chiamata della medesima funzione...

Non capisco quale sia il problema... Perchè non posso creare molti puntatori?
Eppure lo spazio utilizzato dal modello di prova è realmente esiguo (poco meno di 320 bytes)

Posto di seguito la funzione per il caricamento del modello:


int cobFILE::LoadModel(char *fname)
{
FILE *f;
f = fopen(fname, "r+");
int meshes, mats;
int meshi = 0;
int mati = 0;

if(!f)
return 1; //FILE NOT FOUND
//READ HEADER
fread(&this->Header, sizeof(cobHEADER), 1, f);

if(this->Header.Ident[0] != 'C' || this->Header.Ident[1] != 'O' || this->Header.Ident[2] != 'B')
{
fclose(f);
return -1; //THIS IS NOT A VALID FORMAT
}

//ALLOCATE MEMORY
meshes = this->Header.nMeshes;
mats = this->Header.nMaterials;
if(meshes > 0)
{
this->MeshList = (cobMESH *)malloc(sizeof(cobMESH) * meshes);
//memset(this->MeshList, 0, sizeof(cobMESH) * meshes);
}

if(mats > 0)
{
this->MaterialList = (cobMATERIAL *)malloc(sizeof(cobMATERIAL) * mats);
//memset(this->MaterialList, 0, sizeof(cobMATERIAL) * mats);
}

//READ MODEL
while(!feof(f))
{
char chunkID = 0;
fread(&chunkID, sizeof(char), 1, f);
switch(chunkID)
{
case cob_MESH: //IT IS A MODEL!
{
int i;
cobMESH *msh = (cobMESH *)((long)this->MeshList + (long)(sizeof(cobMESH) * meshi));
if(msh == NULL)
{
fclose(f);
return -2; //ERROR IN ALLOCATING MEMORY STORAGE
}
msh->FaceList = (int *)malloc(sizeof(int) * msh->nFaces * 3);
msh->VertexList = (cobVECTOR *)malloc(sizeof(cobVECTOR) * msh->nVertices);

fread(&msh->nVertices, sizeof(int), 1, f);
fread(&msh->nFaces, sizeof(int), 1, f);
fread(&msh->posX, sizeof(float), 1, f);
fread(&msh->posY, sizeof(float), 1, f);
fread(&msh->posZ, sizeof(float), 1, f);
fread(&msh->rotX, sizeof(float), 1, f);
fread(&msh->rotY, sizeof(float), 1, f);
fread(&msh->rotZ, sizeof(float), 1, f);
fread(&msh->scalX, sizeof(float), 1, f);
fread(&msh->scalY, sizeof(float), 1, f);
fread(&msh->scalZ, sizeof(float), 1, f);
fread(&msh->useMaterial, sizeof(int), 1, f);
fread(&msh->MatID, sizeof(int), 1, f);
for(i = 0; i < msh->nVertices; i++)
{
cobVECTOR *v;
float x, y, z;
fread(&x, sizeof(float), 1, f);
fread(&y, sizeof(float), 1, f);
fread(&z, sizeof(float), 1, f);
v = (cobVECTOR *)((long)msh->VertexList + (long)(sizeof(cobVECTOR) * i));
v->x = x;
v->y = y;
v->z = z;
_asm{ nop }

}





for(i = 0; i < msh->nFaces * 3; i++)
{
int *v;
int x;
fread(&x, sizeof(int), 1, f);
v = (int *)((long)msh->FaceList + (long)(sizeof(int) * i));
*(v) = x;
_asm{ nop }

}



}


}
}

fclose(f);
return 0; //MODEL LOADED
}

kingmastermind
09-12-2007, 09:25
All'inizio del programma, a mio parere, dopo avere definito le "class" e le "struct" devono essere dichiarate le variabili "complesse" che poi utilizzerai in cobFILE

cobMESH *this->MeshList;
cobMATERIAL *this->MaterialList;
...... eccetera
sinceramente nel tuo listato non le ho viste inizializzate! correggimi se sbaglio ! Spero di esserti stato di aiuto!

IceCoder
09-12-2007, 09:33
quelle le inizializza il costruttore richiamando memset()

il punto è che dopo che il modello è stato caricato io avvio glut e richiamando glutCreateWindow() il programma crasha e il debugger mi riporta al sorgente di malloc

mi succede sempre, è la terza volta che ricomincio da zero tutto il progetto pensando di aver tralasciato qualcosa.. eppure il problema è sempre di malloc()

ho esaminato altri sorgenti per caricare modelli 3D ma non trovo grandi differenze, anzi il mio modello mi risulta anche meno esteso di altri che allocano decine di puntatori.

Mi è venuto il dubbio che sia un problema di heap ma alloco meno di 320 bytes!

Ho chiesto anke in altri forum ma nessuno riesce a rispondermi :(

cionci
09-12-2007, 09:38
Prima di tutto: perché usi malloc invece di new ?

IceCoder
09-12-2007, 09:49
Prima di tutto: perché usi malloc invece di new ?

ti giuro: se mi avessi risposto 2 mesi fa ti sarei uscito dal lettore floppy per ringraziarti :D

ho risolto in questo modo proprio qlk secondo fa asd

grazie 1000:sofico: :sofico: :sofico: :sofico:

ma...gia che ci siamo...sapete perchè malloc() ha un limite di allocazione?

kingmastermind
09-12-2007, 09:49
Sinceramente non capisco come possa il costruttore inizializzare una variabile complessa e non dichiarata con memset. Atteso che questo avvenga (memset non lo uso mai!) , guarda che quelle variabili, se il programma è scrittto in C++, il programma le utilizza solo ed esclusivamente in ambito funzione cobFILE(), mentre non ti da accesso ad esse da altre funzioni e va in crash, ecco perchè ti consiglio di dichiararle come variabili globali all'inizio del programma! Se questo lo hai già fatto allora non so come aiutarti davvero ! Ciao !;)

IceCoder
09-12-2007, 09:52
Sinceramente non capisco come possa il costruttore inizializzare una variabile complessa e non dichiarata con memset. Atteso che questo avvenga (memset non lo uso mai!) , guarda che quelle variabili, se il programma è scrittto in C++, il programma le utilizza solo ed esclusivamente in ambito funzione cobFILE(), mentre non ti da accesso ad esse da altre funzioni e va in crash, ecco perchè ti consiglio di dichiararle come variabili globali all'inizio del programma! Se questo lo hai già fatto allora non so come aiutarti davvero ! Ciao !;)

se intendi allocarle lo faceva malloc() ora sostituito da new :D

ma era memset() che le inizializzava a zero.

cionci
09-12-2007, 09:55
ecco perchè ti consiglio di dichiararle come variabili globali all'inizio del programma!
Variabili globali in C++ ? :eekk:
ti giuro: se mi avessi risposto 2 mesi fa ti sarei uscito dal lettore floppy per ringraziarti :D

ho risolto in questo modo proprio qlk secondo fa asd

grazie 1000:sofico: :sofico: :sofico: :sofico:

ma...gia che ci siamo...sapete perchè malloc() ha un limite di allocazione?
In teoria il problema potrebbe esserci ancora o magari è rimasto nascosto, anche perché non sono a conoscenza di limiti di malloc rispetto a new. Magari avranno una diversa politica di allocazione e questo rende il problema, almeno pero ora, non visibile.

cionci
09-12-2007, 10:00
Quello che noto è che ci sono mooooolti problemi strutturali nel codice. Stai programmando in C++ "alla C". C++ è un linguaggio ad oggetti.
Ad esempio l'information hiding impone di non rendere pubbliche le variabili membro.
In ogni caso quella classe fa troppe cose...fa sia da repository che da loader.
Prima di tutto farei una buona riorganizzazione del codice e poi dopo penserei a ricercare quel bug.

kingmastermind
09-12-2007, 10:02
Egregio moderatore, scusa se sono stato un poco bricconcello nell'esprimermi, eppure qualcosa ne capisco anche io di C++ ! questo è il mio sito, con i miei programmi, dagli un occhiata ! forse di C++ ne capisco abbastanza anche io!

http://www.winturtle.netsons.org/

IceCoder
09-12-2007, 10:02
Variabili globali in C++ ? :eekk:



beh in effetti direi che è improbabile che un programmatore usi le globali in c++ scrivendo un motore grafico visto e considerato che il numero di modelli è indefinito e poi ogni livello contiene milioni di vertici e decine di oggetti di tipo differente (oggetti mobili, materiali, luci, statici, listati di animazioni, matrici, ecc...) sarebbe un po proibitivo.

IceCoder
09-12-2007, 10:08
ah forse ho capito cosa intendi.. se intendi strutture globali e funzioni che operano sulle strutture anzicchè classi che contengono funzioni e strutture puo anche essere utilizzabile come metodo però quando lavori con collisioni, suoni, animazioni e compagnia bella c'è da uscire pazzi O.O

EDIT: scusate il doppio post

cionci
09-12-2007, 10:12
Egregio moderatore, scusa se sono stato un poco bricconcello nell'esprimermi, eppure qualcosa ne capisco anche io di C++ ! questo è il mio sito, con i miei programmi, dagli un occhiata ! forse di C++ ne capisco abbastanza anche io!
Guarda non voglio assolutamente insinuare che tu non sappia il C++, sto solo dicendo che le variabili globali vanno contro praticamente tutte le regole dell'ingegneria del software ;) Pensa che molti dei programmatori che conosco evitano anche di usare il design pattern singleton perché a loro modo dire è come buttare fuori le variabili globali dalla porta e reinserirle dalla finestra :)

Al massimo posso capire che possa essere una variabile globale l'istanza della classe che rappresenta l'engine grafico (ma personalmente nemmeno quello lo metterei globali) in un'applicazione 3D, ma già i repository di mesh e materiali devono essere contenuti all'interno dell'engine stesso e non essere globali.

kingmastermind
09-12-2007, 10:15
Mi scuso, se sono stato poco chiaro prima, per variabile globale io intendo qualsiasi variabile inizializzata all'inizio del programma (es. unsigned char x; ), che può essere tranquillamente utilizzata da qualsiasi funzione! Purtroppo il C++ permette ad esempio di dichiarare la varilabile x sia all'inizio del programma, sia in una qualsiasi funzione o procedura che tu crei (es. cobFILE)! Risultato: bisogna stare attenti poi a verificare quale abbia precedenza tra le due nella singola funzione o nella Main()! E' un casino! ed allora preferisco sempre dichiararle all'inizio e non ri-utilizzarle assolutamente nelle funzioni! Le variabili globali di cui tu parli sono più incasinate e sta a te vedere se utilizzarle o meno!

cionci
09-12-2007, 10:31
IceCoder: la classe cobFILE ha troppe responsabilità. Fa sia da loader che da repository.
Quindi una organizzazione minima alternativa potrebbe essere questa.

class cobFileLoader
{
//per ora possiamo fare un method object
CobFileLoader();

//metodi privati per suddividere le varie operazioni
static int loadHeader(ifstream &file, cobHeader &header);
static int loadMeshes(ifstream &file, cobMeshes &meshes);
static int loadMaterials(ifstream &file, cobMaterials &materials);
public:
static int Load(string fileName, cobHeader &header, cobMaterials &materials, cobMeshes &meshes);
};

class cobObject
{
cobHeader header;
cobMaterials materials;
cobMeshes meshes;
AbsolutePosition position;

cobObject(); //costruttore di default privato
public:
cobObject(const cobObject &object); //costruttore di copia per copiare gli oggetti
//factory method: dovrà essere chiamato da chi vuole costruire l'oggetto
static cobObject LoadFromCobFile(const string &fileName);
//ora non so cosa vuoi fare con questi dati, ma ad esempio:
void moveBy(float dx, float dy, float dz);
void moveTo(AbsolutePosition p);
codHeader & getHeader();
cobMaterials & getMaterials();
cobMeshes & getMeshes();
AbsolutePosition & getAbsolutePosition();
}

//per completezza implemento il factory method
static cobObject cobObject::LoadFromCobFile(const string &fileName)
{
cobObject obj;

if(!cobFileLoader::Load(fileName, obj.header, obj.materials, obj.meshes))
{
return NULL;
}
//qui fa uso del costruttore di copia, ma si potrebbe anche evitare per migliorare le prestazioni,
//ma come si dice: early optimization is the root of all evil ;)
return obj;
}


cobHeader header;
cobMaterials materials;
cobMeshes meshes;

L'header può essere anche la struttura dati che hai messo sopra, in quanto è una struttura statica.

cobMaterials e cobMeshes per me devono essere collection. Ad esempio vector delle strutture sopra (nel modo più semplice);

IceCoder
09-12-2007, 10:39
IceCoder: la classe cobFILE ha troppe responsabilità. Fa sia da loader che da repository.
Quindi una organizzazione minima alternativa potrebbe essere questa.

class CobFileLoader
{
//per ora possiamo fare un method object
CobFileLoader();
public:
static int Load(cobHeader &header, cobMaterials &materials, cobMeshes &meshes);
};

class cobObject
{
cobHeader header;
cobMaterials materials;
cobMeshes meshes;
float x, y, z;

cobObject(); //costruttore di default privato
public:
cobObject(const obObject &object); //costruttore di copia per copiare gli oggetti
//factory method: dovrà essere chiamato da chi vuole costruire l'oggetto
static cobObject & LoadFromCobFile(const string &fileName);
//ora non so cosa vuoi fare con questi dati, ma ad esempio:
void moveBy(float dx, float dy, float dz);
void moveTo(AbsolutePosition p);
codHeader & getHeader();
cobMaterials & getMaterials();
cobMeshes & getMeshes();
AbsolutePosition & getAbsolutePosition();
}


cobHeader header;
cobMaterials materials;
cobMeshes meshes;

L'header può essere anche la struttura dati che hai messo sopra, in quanto è una struttura statica.

cobMaterials e cobMeshes per me devono essere collection. Ad esempio vector delle strutture sopra (nel modo più semplice);

beh al momento è solo una classe di prova, sto lavorando ad un estensione (*.cob) mia personale, quindi con l'andare del tempo la perfezionerò. al momento devo solo caricare un modello e fare il rendering per vedere se il programma di conversione funziona bene :P

cionci
09-12-2007, 10:42
beh al momento è solo una classe di prova, sto lavorando ad un estensione (*.cob) mia personale, quindi con l'andare del tempo la perfezionerò. al momento devo solo caricare un modello e fare il rendering per vedere se il programma di conversione funziona bene :P
Ho fatto qualche modifica. In ogni caso è bene organizzare anche le prove in modo corretto...e c'è un motivo: se l'avessi organizzato in modo corretto probabilmente non avresti avuto quell'errore ;)

IceCoder
09-12-2007, 10:49
Ho fatto qualche modifica. In ogni caso è bene organizzare anche le prove in modo corretto...e c'è un motivo: se l'avessi organizzato in modo corretto probabilmente non avresti avuto quell'errore ;)

gia, è vero ^^