I am trying to learn some c++. To do this I have chosen to write an emulator. I had it up and running, but decided to try to make a better architecture. I have a strange problem that I don't understand. If I compile the following code (Visual C++ 2000 Express Edition) I get an error message: "Unhandled exception at 0x0041183f in test.exe: 0xC0000005: Access violation reading location 0x00000004."

If I cut the code from cpu.cpp and paste in main.cpp it is working. Can somebody try to explain to me what is the problem with my code/design?

main.h

typedef unsigned char u8;
typedef unsigned short u16;

// Forward declare the required classes
class Cpu;
class Memory;

class Gameboy
{
public:
	Cpu *cpu;
	Memory *memory;

	Gameboy();
	~Gameboy();
	void Start();
};

static Gameboy *gb;

class Memory
{
public:
	u8 read(u16 addr) const;
	void write(u16 addr, u8 value);
private:
	u8 _memory[0xffff];
};

class Cpu {
public:
	void Run();
};

main.cpp

#include <iostream>
#include "main.h"

int main(int argc, char *argv[])
{
    gb = new Gameboy();
	gb->Start();
	system("PAUSE");
	return 0;
}

u8 Memory::read(u16 addr) const { return _memory[addr];}
void Memory::write(u16 addr, u8 value) { _memory[addr] = value; }
Gameboy::Gameboy() { this->cpu = new Cpu(); this->memory = new Memory(); }
Gameboy::~Gameboy() { delete cpu; delete memory; }
void Gameboy::Start() {	cpu->Run(); }

cpu.cpp

#include <iostream>
#include "main.h"

void Cpu::Run() {
	gb->memory->write(0xff40, 0x10);
	printf("[Debug] 0xff40: %.2X\n", gb->memory->read(0xff40));
}

Where is my crystall ball? No codes in your snippet. You may present excellent function prototype but where is this function body?
It's interesting, can you help me right now: I have some troubles with my car (well, I haven't), help me, please! ;)

No need for crystal ball. All the code is there. I have pasted 3 files. The functions are small since I tried to only include what is nessessary to reproduce the problem.

main.h with all the class definitions and function prototypes. main.cpp contains all function, except for void Cpu::Run() which is in a separate file, cpu.cpp.

The reason for this is that if everything is in one file it is working, and the printf in void Cpu::Run() gives me the expected output. If I try to start separating the classes into individual files, I get the error message described. In this example I have only moved the void Cpu::Run() from main.cpp to cpu.cpp, and it is causing me problems.

Oh, I did not found these crumpled bodies, sorry.

It's so simple: you have declared static gb pointer in main.h (never, ever do it again). It's a module scope variable: gb from main.cpp is not the same as gb from cpu.cpp. That's all: you refer to nullptr initialized gb in cpu.cpp...

OK thanks for the reply. Seems like I misunderstood the 'static' a bit. How would I go ahead and declare this if I want it as a global variable? If I define it in a header file, the linker complains about it being declared several places.

What I want is a Gameboy class which contains memory, cpu etc classes. How can I then access functions in memory from e.g. cpu? Should I pass the *gb as part of the constructor or something.

Anyone have a prefered solution for that?

you never really want to define a global variable. if the variable is to travel around you can declare it in you main.cpp file in the int main() function as a pointer and then pass it around to your different functions and classes as a pointer.

void Cpu::Run(GameBoy * gb)

then you will have your gb object in main() and you can have it in Cpu::Run()

There are lots of possible solutions.
The worst: global variable.
main.h file:

extern Gameboy* gb; // global var declaration

main.cpp:

Gameboy* gb; // nullptr initial value (global var definition)

Another (more consistent) approach (variant):

class Debugger;
class Processor
{
    friend class Debugger; // future improvements...
public:
    Processor():busy(false) {}
    ...
    void Run();
    bool lock() { return busy?false:(busy=true); }
    vool locked() const { return busy; }
    void unlock() { busy = false; }
    ...
private:
    Cpu cpu;
    Memory memory;
    bool busy;
};
...
class Gameboy
{
public:
    Gameboy():proc(0) {}
    ...
    bool attach(Processor& p)
    {
        if (p.locked())
            return false;
        proc = &p;
        return p.lock();
    }
    Processor* detach()
    {
        Processor* p = proc;
        proc = 0;
        return p;
    }
    void Play();
    void Start() { Play(); } // (backward compatibility ;)
    ...
private:
    Processor* proc;
};

and so on...

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.