Sign in to follow this  
EvilNando

only on DEBUG this code crashes

Recommended Posts

EvilNando    96
[code]
int main()
{
ifstream _file_input("GameData.dat", ios::binary);
for (int _idx = 0; _idx < 3; _idx++)
{
//cout<<"size of Monster "<<sizeof(GameMonster)<<" ";
//cout<<"current seek pointer position :"<<_file_input.tellg()<<endl;

//_file_input.seekg(_idx * sizeof(GameMonster));
_file_input.read((char*)&_monster, sizeof(GameMonster));

cout<<_monster.Damage<<" "<<_monster.Hp<<" "<<_monster.Name<<endl;
}

_file_input.close();

cout<<"\nPress a key"<<endl;
getchar();
// PAST THIS LINE THE PROGRAM CHRASHES
}
[/code]

the error
Unhandled exception at 0x581fad4a (msvcp100d.dll)
0xC0000005: Access violation reading location 0x00a94be4

if I switch to release the code runs just fine, pretty weird huh?

Share this post


Link to post
Share on other sites
Hodgman    51237
It's not weird, it's common of bugs relating to uninitialized memory, or memory corruption -- the debug build includes extra checks to try and [i]make [/i]bad code crash, so that you realize that you've got some kind of corruption going on.

Where/what is [font="Lucida Console"]_monster[/font]?

Share this post


Link to post
Share on other sites
bubu LV    1436
Is _monster really an object of class/struct GameMonster? And what type are Damage, Hp and Name members of _monster object?
Are there some other global variables with non-trivial constructor or destructor in your program?

Share this post


Link to post
Share on other sites
SiCrane    11839
Whether or not it's weird depends on what your GameMonster type looks like. If it's non-POD, then it's not weird at all.

Share this post


Link to post
Share on other sites
EvilNando    96
heres the full soruce

maybe something Im missing?

[code]


#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <fstream>

using namespace std;

class GameMonster
{
public:
string Name;
int Hp;
int Damage;

GameMonster() { Name = ""; Hp = 0; Damage = 0; }
GameMonster(string name, int hp, int dmg) { Name = name; Hp = hp; Damage = dmg; }
};


class GameNpc
{
public:
string Name;
int Hp;
int Damage;
string SpecialAttack;

GameNpc() { Name = ""; Hp = 0; Damage = 0; SpecialAttack = ""; }
GameNpc(string name, int hp, int dmg, string specialAtk) { Name = name; Hp = hp; Damage = dmg; SpecialAttack = specialAtk; }
};



void main()
{
GameMonster _monster;
GameMonster _monsters[3] = { GameMonster("Troll", 50, 20), GameMonster("Skeleton", 10, 5), GameMonster("Rat", 5, 1) };
GameNpc _npcs[3] = { GameNpc("Gawein", 100, 25, "Smity"), GameNpc("Vivi", 25, 5, "LulzSkillz"), GameNpc("Necro", 40, 2, "Raise Dead") };

ofstream _file("GameData.dat", ios::binary);

_file.write((char*)_monsters, sizeof(_monsters));

_file.seekp(0, ios::end);
cout<<"size of GameData.dat "<<_file.tellp()<<" bytes"<<endl<<endl;

_file.close();



ifstream _file_input("GameData.dat", ios::binary);
for (int _idx = 0; _idx < 3; _idx++)
{
cout<<"size of Monster "<<sizeof(GameMonster)<<" ";
cout<<"current seek pointer position :"<<_file_input.tellg()<<endl;

//_file_input.seekg(_idx * sizeof(GameMonster));
_file_input.read((char*)&_monster, sizeof(GameMonster));

cout<<_monster.Damage<<" "<<_monster.Hp<<" "<<_monster.Name<<endl;
}

_file_input.close();

cout<<"\nPress a key"<<endl;
getchar();
}
[/code]

Share this post


Link to post
Share on other sites
SiCrane    11839
std::string is non-POD, and since your classes contain it, your classes are non-POD. This means that you can't just copy the bits that make it up to a file and read it back. You need to do actual serialization.

Share this post


Link to post
Share on other sites
SiCrane    11839
[url=http://www.fnal.gov/docs/working-groups/fpcltf/Pkg/ISOcxx/doc/POD.html]The first link when I put "POD C++" into google[/url].

Share this post


Link to post
Share on other sites
EvilNando    96
The links says nothing about how to fix the problem so Ill ask again

should I use fixed char arrays instead or is there an actual way of reading std::strings of variable size using ifstream

<div><br></div><div><br></div><div>edit: I just tried using very long strings just to test what happened if I varied each of the monsters actual byte size but it still working properly (without considering the crash at the end of program)</div>

Share this post


Link to post
Share on other sites
SiCrane    11839
[quote name='EvilNando' timestamp='1310899151' post='4836318']
should I use fixed char arrays instead or is there an actual way of reading std::strings of variable size using ifstream
[/quote]
[url=http://www.parashift.com/c++-faq-lite/serialization.html]The first link when I throw "C++ serialization" into google[/url].

Share this post


Link to post
Share on other sites
Wooh    1088
You can use std::string, all you have to do is writing each variable in GameMonster one at a time

[code]#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <fstream>

using namespace std;

class GameMonster
{
public:
string Name;
int Hp;
int Damage;

GameMonster() { Name = ""; Hp = 0; Damage = 0; }
GameMonster(string name, int hp, int dmg) { Name = name; Hp = hp; Damage = dmg; }
};



int main()
{
GameMonster _monster;
GameMonster _monsters[3] = { GameMonster("Troll", 50, 20), GameMonster("Skeleton", 10, 5), GameMonster("Rat", 5, 1) };

ofstream _file("GameData.dat", ios::binary);

for (int i = 0; i < 3; i++)
{
int nameLength = _monsters[i].Name.size();
_file.write((char*)&nameLength, sizeof(int));
_file.write(_monsters[i].Name.c_str(), _monsters[i].Name.size());
_file.write((char*)&_monsters[i].Hp, sizeof(int));
_file.write((char*)&_monsters[i].Damage, sizeof(int));
}


_file.seekp(0, ios::end);
cout<<"size of GameData.dat "<<_file.tellp()<<" bytes"<<endl<<endl;

_file.close();


ifstream _file_input("GameData.dat", ios::binary);
for (int _idx = 0; _idx < 3; _idx++)
{
cout<<"size of Monster "<<sizeof(GameMonster)<<" ";
cout<<"current seek pointer position :"<<_file_input.tellg()<<endl;

int nameLength;
_file_input.read((char*)&nameLength, sizeof(int));
_monster.Name.resize(nameLength);
_file_input.read(&_monster.Name[0], nameLength);
_file_input.read((char*)&_monster.Hp, sizeof(int));
_file_input.read((char*)&_monster.Damage, sizeof(int));

cout<<_monster.Damage<<" "<<_monster.Hp<<" "<<_monster.Name<<endl;
}

_file_input.close();

cout<<"\nPress a key"<<endl;
getchar();
}[/code]

Share this post


Link to post
Share on other sites
rip-off    10976
To make it easier, consider writing helper functions:
[code]
// Some IO Helper header
namespace detail
{
template<typename Type>
std::istream &readPOD(std::istream &in, Type &instance)
{
char *pointer = reinterpret_cast<char *>(&instance);
return in.read(pointer, sizeof(instance));
}

template<typename Type>
std::ostream &writePOD(std::ostream &out, const Type &instance)
{
const char *pointer = reinterpret_cast<const char *>(&instance);
return out.write(pointer, sizeof(instance);
}
}

std::istream &read(std::istream &in, int &i)
{
return detail::readPOD(in, i);
}

std::istream &read(std::istream &in, std::string &s)
{
int count;
if(read(in, count))
{
vector<char> data;
data.resize(count);
if(in.read(&data.front(), count))
{
s.assign(data.begin(), data.end());
}
}
return in;
}

std::istream &write(std::ostream &out, int i)
{
return detail::write(out, i);
}

std::istream &write(std::ostream &out, const std::string &s)
{
int n = s.size();
write(n);
return out.write(s.c_str(), n);
}

// Monster

void read(std::istream &in, Monster &monster)
{
if(!(read(monster.Hp) && read(monster.Damage) && read(monster.Name)))
{
// error handling?
}
}

void write(std::ostream &out, const Monster &monster)
{
if(!(write(monster.Hp) && write(monster.Damage) && write(monster.Name)))
{
// error handling?
}
}
[/code]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this