• Advertisement
Sign in to follow this  

Need help to read objects from file and push them back into a list container .

This topic is 3039 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

What I am trying to do is write objects from an STL list container to a file and then read them back in and load them back into the container for manipulation. It seems that I have accomplished that except the program crashes when I try to load the objects into the container. The save(write) and load(read) operations have been made members of the Block class.
 

//this is my container /iterator setup 
Block* Obj;
list<Block*> Blocks;
list<Block*>::iterator it; 



//this is the constructor I am using to create the objects

Block::Block() :
MyId(GetMyId()),MyX(GetMyX()),MyY(GetMyY()),MyZ(GetMyZ()),MyWidth(GetMyWidth()),
MyHeight(GetMyHeight()),MyScore(GetMyScore()),MyR(GetMyR()),MyG(GetMyG()),MyB(GetMyB()),ISelected(false)              
{MyId = MyNum;MyNum++;InitBlocks();}



//This is called by the save function

void Block::WriteData(){                       
 ofstream out;
 out.open("Level.dat",ios::app | ios::binary );
 out.write((char*)this, sizeof(*this));
}


//This is the function that gets called to read the objects back in to push them back into the list //container.

void Block::ReadData(unsigned int mid){
 ios;
 ifstream in;
 in.open("Level.dat",ios::binary);
 in.seekg( mid*sizeof(Block) );         //move file ptr
 in.read( (char*)this, sizeof(*this) );
     
}

// This is the function that counts how many objects are stored in the file.This is a static function

unsigned int Block::BlockCount(){
 ifstream in;
 in.open("Level.dat",ios::binary);
 in.seekg(0, ios::end);    //go to 0 bytes from end
				 //calculate number of Blocks
   return (unsigned int)in.tellg() / sizeof(Block);
 
}


//this is my load function that is called when I click a button.  

void LoadFile(){
if(!Blocks.empty()){
Blocks.clear();
}
Obj->Load = true;                     //this is a static bool
int n = Block::BlockCount();
for(int i=0;i<n;i++){
Obj->ReadData(i);
//Obj = new Block();
Blocks.push_back(Obj);
(*it)->drawMe = true;
(*it)->ISelected = false;
}

//this is my save function that is called when I click a button.All it does is call the 
WriteData() member function

void SaveMe(){
for(it = Blocks.begin();it != Blocks.end();++it){
(*it)->WriteData();
}
}



I don't know if this is enough info for someone to be able to help me with this or not. I am rather new to the OOP part of c++, any help on this would be greatly appreciated. Much Thanks, Jody Bush [Edited by - bushimports on October 29, 2009 10:22:31 PM]

Share this post


Link to post
Share on other sites
Advertisement
First: for posting larger amounts of code, use [ source] [ /source] tags (without the spaces). It makes your code more readable. See the faq (upper-right-corner this page). Click EDIT on this post to see how it's done.
Quote:
the program crashes when I try to load the objects into the container

At which line does it "crash?" What do you mean by "crash?" What error do you get?

1. What do you init the data file? I.e., do you only add to it or do you clear it at some point?

2. After your SaveMe(), does BlockCount return the correct value?

3. You clear the Block vector, but you don't delete the pointers it contains. Are you running out of memory?

4. It doesn't appear you initialize Obj anywhere. It would appear you should be setting Obj = new Block for every read.

You need some modifications, something like:

if(!Blocks.empty()){ // delete all the old objects
for(int i=0; i<(int)Blocks.size(); i++) delete Blocks;
Blocks.clear();
}
...
for(int i=0;i<n;i++){
Obj = new Block;
Obj->Load = true; // what's this for?? why static?
Obj->ReadData(i);
Obj->drawMe = true;
Obj->ISelected = false;
Blocks.push_back(Obj);
// iterator hasn't been initialized and isn't needed
//(*it)->drawMe = true;
//(*it)->ISelected = false;
}


Share this post


Link to post
Share on other sites
Show the declaration of the class itself. (In particular, I want to see the types of the data members.)

Share this post


Link to post
Share on other sites
Actually I was not sure if I was supposed to recreate the blocks with new or if I was just supposed to read the objects back from the file and push them into the container.
I thought I was initializing Obj,Blocks, and the iterator with
 Block* Obj;list<Block*> Blocks;list<Block*>::iterator;
I guess all I did there is declare them, I guess I don't know what you mean by initializing them. The way I have done it is the way I have always seen it done in the book I have been reading, it is possible I missed something. As far as what line the program crashes on is concerned, I don't know. I am using Dev c++ on this because I had a problem with visual studio on a redefinition of exit with glut. Usually I can just include cstdlib above all my other includes and that fixes the problem but not always. This was one of the exceptions. I have not yet been able to get the Dev c++ debugger to do anything that made sense to me, and I really don't have much experience debugging. By crashing I mean when I hit the load button windows pops up a message box that say the application has encountered a problem and needs to close, then the program shuts down.


//Here is My Block Class declaration

#ifndef BLOCK_HPP
#define BLOCK_HPP
#include<GL/glut.h>
#include <list>
#include <iostream>

class Block{
private:
int ww,wh,MyLevel,MyScore;
unsigned int MyId;
static unsigned int MyNum,VBlockCount,HBlockCount;
static float gapp;
float MyX,MyY,MyZ,MyWidth,MyHeight,MyR,MyG,MyB;
void InitBlocks();
public:
Block();
~Block();
void DrawMe();
inline int GetVCount(){return this->VBlockCount;}
inline int GetHCount(){return this->HBlockCount;}
inline unsigned int GetMyId(){return this->MyId;}
inline float GetMyX(){return this->MyX;}
inline float GetMyY(){return this->MyY;}
inline float GetMyZ(){return this->MyZ;}
inline float GetMyWidth(){return this->MyWidth;}
inline float GetMyHeight(){return this->MyHeight;}
inline float GetGap(){return gapp;}
inline float GetMyR(){return this->MyR;}
inline float GetMyG(){return this->MyG;}
inline float GetMyB(){return this->MyB;}
inline int GetMyScore(){return this->MyScore;}
inline int GetMyLevel(){return this->MyLevel;}

inline void SetMyX(float my_x){ this->MyX = my_x;}
inline void SetMyY(float my_y){ this->MyY = my_y;}
inline void SetMyZ(float my_z){ this->MyZ = my_z;}
inline void SetMyWidth(float my_width){this->MyWidth = my_width;}
inline void SetMyHeight(float my_height){this->MyHeight = my_height;}
inline void SetMyR(float my_r){ this->MyR = my_r;}
inline void SetMyG(float my_g){ this->MyG = my_g;}
inline void SetMyB(float my_b){ this->MyB = my_b;}
inline static void SetGap(float gap){gapp = gap;}
inline void SetMyScore(int my_score){this->MyScore = my_score;}
inline void SetMyLevel(int my_level){this->MyLevel = my_level;}
inline static void SetGap(float gap){gapp = gap;}
inline static unsigned int SetVBlockCount(unsigned int vbc){VBlockCount = vbc;}
inline static unsigned int SetHBlockCount(unsigned int hbc){HBlockCount = hbc;}
void LoadBlocks();
void WriteData();
static unsigned int BlockCount();
void ReadData(unsigned int mid);
void ShowData(void);
static void Reset();
bool ISelected;
bool drawMe;
bool Highlight;
static bool Load;

};
#endif

//Here is the class definition/implementation
#include "Block.hpp"
#include <iostream>
#include <fstream>

using namespace std;

unsigned int Block::MyNum = 0;
unsigned int Block::VBlockCount = 0;
unsigned int Block::HBlockCount = 0;
bool Block::Load = false;
float Block::gapp = 0;

Block::Block() :
MyId(GetMyId()),MyX(GetMyX()),MyY(GetMyY()),MyZ(GetMyZ()),MyWidth(GetMyWidth()),
MyHeight(GetMyHeight()),MyScore(GetMyScore()),MyR(GetMyR()),MyG(GetMyG()),MyB(GetMyB()),ISelected(false)
{MyId = MyNum;MyNum++;InitBlocks();}


Block::~Block(){
cout << "Deleting " << MyId << "\n";
}

void Block::Reset(){
Block::MyNum = 0;
Block::VBlockCount = 0;
Block::HBlockCount = 0;
Block::gapp = 0;
}


void Block::WriteData(){
ofstream out;
out.open("Level.bsp",ios::app | ios::binary );
out.write((char*)this, sizeof(*this));
}


void Block::ReadData(unsigned int mid){
ifstream in;
in.open("Level.bsp",ios::binary);
in.seekg( mid*sizeof(Block) ); //move file ptr
in.read( (char*)this, sizeof(*this) );
}


unsigned int Block::BlockCount(){
ifstream in;
in.open("Level.bsp",ios::binary);
in.seekg(0, ios::end); //go to 0 bytes from end
return (unsigned int)in.tellg() / sizeof(Block);//calculate number of Blocks
}

void Block::LoadBlocks(){
int n = BlockCount();
for(int i=0;i<n;i++){
ReadData(i);
drawMe = true;
ISelected = false;
}
}

void Block::InitBlocks(){
if(Load == true){
LoadBlocks();
}
else{
ww = glutGet(GLUT_SCREEN_WIDTH);
MyZ = 0.0;

MyWidth = ((ww-(gapp*(HBlockCount-1)))/HBlockCount);
MyHeight = ((200/VBlockCount)-((VBlockCount-1)*gapp));
if((MyId >= 0) && (MyId < HBlockCount)){
MyX = (((float)MyId*MyWidth)+((float)MyId*gapp));
MyY = 100.0;
}
if((MyId >= HBlockCount) && (MyId < (HBlockCount*2))){
MyX = (((MyId-HBlockCount)*MyWidth) + ((MyId-HBlockCount)*gapp) );
MyY = 100.0 + gapp + MyHeight;
}
if((MyId >= HBlockCount*2) && (MyId < (HBlockCount*3))){
MyX = (((MyId-HBlockCount*2)*MyWidth) + ((MyId-HBlockCount*2)*gapp) );
MyY = 100.0 + (gapp*2) + (MyHeight*2);
}
if((MyId >= HBlockCount*3) && (MyId < (HBlockCount*4))){
MyX = (((MyId-HBlockCount*3)*MyWidth) + ((MyId-HBlockCount*3)*gapp) );
MyY = 100.0 + (gapp*3) + (MyHeight*3);
}
if((MyId >= HBlockCount*4) && (MyId < (HBlockCount*5))){
MyX = (((MyId-HBlockCount*4)*MyWidth) + ((MyId-HBlockCount*4)*gapp) );
MyY = 100.0 + (gapp*4) + (MyHeight*4);
}
if((MyId >= HBlockCount*5) && (MyId < (HBlockCount*6))){
MyX = (((MyId-HBlockCount*5)*MyWidth) + ((MyId-HBlockCount*5)*gapp) );
MyY = 100.0 + (gapp*5) + (MyHeight*5);
}
if((MyId >= HBlockCount*6) && (MyId < (HBlockCount*7))){
MyX = (((MyId-HBlockCount*6)*MyWidth) + ((MyId-HBlockCount*6)*gapp) );
MyY = 100.0 + (gapp*6) + (MyHeight*6);
}
if((MyId >= HBlockCount*7) && (MyId < (HBlockCount*8))){
MyX = (((MyId-HBlockCount*7)*MyWidth) + ((MyId-HBlockCount*7)*gapp) );
MyY = 100.0 + (gapp*7) + (MyHeight*7);
}
if((MyId >= HBlockCount*8) && (MyId < (HBlockCount*9))){
MyX = (((MyId-HBlockCount*8)*MyWidth) + ((MyId-HBlockCount*8)*gapp) );
MyY = 100.0 + (gapp*8) + (MyHeight*8);
}
if((MyId >= HBlockCount*9) && (MyId < (HBlockCount*10))){
MyX = (((MyId-HBlockCount*9)*MyWidth) + ((MyId-HBlockCount*9)*gapp) );
MyY = 100.0 + (gapp*9) + (MyHeight*9);
}
if((MyId >= HBlockCount*10) && (MyId < (HBlockCount*11))){
MyX = (((MyId-HBlockCount*10)*MyWidth) + ((MyId-HBlockCount*10)*gapp) );
MyY = 100.0 + (gapp*10) + (MyHeight*10);
}
if((MyId >= HBlockCount*11) && (MyId < (HBlockCount*12))){
MyX = (((MyId-HBlockCount*11)*MyWidth) + ((MyId-HBlockCount*11)*gapp) );
MyY = 100.0 + (gapp*11) + (MyHeight*11);
}
if((MyId >= HBlockCount*12) && (MyId < (HBlockCount*13))){
MyX = (((MyId-HBlockCount*12)*MyWidth) + ((MyId-HBlockCount*12)*gapp) );
MyY = 100.0 + (gapp*12) + (MyHeight*12);
}
}
}

void Block::DrawMe(){
if(Highlight == true){
glColor3f(1.0,0.0,0.0);
}
else
glColor3f(MyR,MyG,MyB);
glPushMatrix();
glBegin(GL_QUADS);
glVertex3f(MyX,MyY,MyZ);
glVertex3f(MyX+MyWidth,MyY,MyZ);
glVertex3f(MyX+MyWidth,MyY+MyHeight,MyZ);
glVertex3f(MyX,MyY+MyHeight,MyZ);
glEnd();
glPopMatrix();
if(ISelected == true){
glColor3f(1.0,0.0,0.0);
glPushMatrix();
glBegin(GL_LINE_LOOP);
glVertex3f(MyX,MyY,MyZ);
glVertex3f(MyX+MyWidth,MyY,MyZ);
glVertex3f(MyX+MyWidth,MyY+MyHeight,MyZ);
glVertex3f(MyX,MyY+MyHeight,MyZ);
glEnd();
glPopMatrix();

}
}



Thanks guys I really appreciate the help, Jody Bush







Share this post


Link to post
Share on other sites
Good thing Zahlman asked to post your class. You've got a FUBAR constructor.

A constructor is called when a class is instantiated. None of its variables are defined at that point. As a result, your constructor loads MyX with GetMyX() which returns an undefined value. Not good. You need to supply values for the constructor, or the constructor should initialize all the variables with some default values. You definitely don't want to be initializing each variable with its undefined self!
Quote:
The way I have done it is the way I have always seen it done in the book I have been reading, it is possible I missed something.

You missed something. [WINK]

Share this post


Link to post
Share on other sites
When you fix your constructor I would recommend reducing that parameter list. Either only set the complete relevant things in the constructor and use Set/Get functions to set the rest. Create structs to combine similar variables like X,Y,Z. There are a lot of things you could do there but that big of a parameter list would just get to be a pain in the arse and it would not look that pretty/get confusing. Just my .02 hope it helps

Also I am assuming you would want more then 1 block considering your using a list. So what you could do is create a loader function for the block.. that would do what the constructor does currently (or tries to).. and use your constructor for initilizing values that you know will always be atleast a certian value... like setting a bool m_isDead; to m_isDead(false) whenever your create a block because your assuming a block is not dead if it has been created... that kind of thing... or you know x y z will always start at 50 , 50 , 50... that kind of thing...soooo...

std::list<Block*> blocklist;

int CreateBlock( )
{
Block* OBj = new Block;
Obj->Load(/*param list here*/);

blocklist.insert( OBj );
}


with that obviously you will have to delete the Block at some time and since I dont want to give you bad code i am not going to create a function that might invalidate the iterator lol.. But essentially create a function erases the Block from the list and then calls delete on that instance of it.. otherwise you have memory leaks..


[Edited by - RanBlade on October 30, 2009 4:18:42 PM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement