1
votes

So I have 3 classes. One main class, ClassA, one base class, ClassB, and one inherited class, ClassC, that work together however, when I close my program I get an 'Access violation writing location' error.

Here is the setup:

ClassA .h

ClassA
{
public:
    ClassA(void) : player_(NULL), bullet_(NULL) {};
    ~ClassA(void);

    void Update();
    void fireBullet(int posx, int posy, int speed);

private:
    ClassB* player_;
    ClassB* bullet_;
};

ClassA .cpp

void ClassA::Update()
{
    ClassA* pointer = this;
    player_->Update(*pointer);

    if(bullet_->IsAlive())
        bullet_->Update(*pointer);
}

void fireBullet(int posx, int posy, int speed)
{
    //make it active, set its position and speed
}

Class B is just the base class so I will only post class C

ClassC .h

ClassC : public ClassB
{
public:
    ClassC() : posx_(0), posy_(0) {};
    virtual void Update(ClassA &a);

private:
    int posx_;
    int posy_;
}

ClassC .cpp

void ClassC::Update(ClassA &a)
{
    if(spacebar == pressed)
        a.fireBullet(posx_, posy_, 10);
}

I feel I have a referencing error somewhere but I don't know where. The problem only occurs when a bullet is spawned so if I don't press spacebar throughout the program and then close it, the program exits gracefully. However if I have pressed spacebar at runtime then it causes the access violation error. I have checked the ClassA destructor but the problem occurs whether there is something in the destructor or not.

I have tried to only show relevant code to the problem. There is an initialse function that to initialise the bullet_ and player_ but don't see it relevent to the problem.

Destructors:

ClassA ClassA::~ClassA(void) { delete player_; delete bullets_; }

ClassB and ClassC

~Class {};

Also player_ and bullet_ are initialised in a function in ClassA:

ClassA::Initialise()
{
    ClassB* player = new ClassC;
    player->Initialise();
    player_ = player;

    ClassB* bullet = new ClassD; //ClassD is also inherited from B
    bullet->Initialise();
    bullet_ = bullet;
}
2
At what point do you ever assign valid addresses to objects to all those pointers? And if Class A appears in any by-value assignment or copy-construction, I'm going with a Rule of Three non-compliance. Check your code carefully (or better still, use smart pointers so you don't have to worry about it.). most of all attach a debugger and debug this. it will happily throw up in your face with a call stack telling you pretty much exactly how you got to where you are (assuming you didn't corrupt the stack). - WhozCraig
Can we see the destructors for A, B and C? - IdeaHat
If you're on Linux, can you try running your program under Valgrind? valgrind.org/docs/manual/quick-start.html - nodakai
The code looks fine. The code which cause the error should be somewhere else: this line of code corrupts the heap, but the error will be shown by the debugger at the next heap operation. - Matt
@WhozCraig I have updated the post. - Daniel

2 Answers

0
votes

One mistake I can notice is that you send ClassA by reference in ClassC::Update(ClassA &a) and you use it after that as a pointer. Try to write

void ClassC::Update(ClassA &a)
{
    if(spacebar == pressed)
        a.fireBullet(posx_, posy_, 10);
}

Also, please send the code for your constructors, destructors, object creation etc.

0
votes

since your program gets access violation after the end. It means that error is in destructor. Sometimes destructors are called without an explicit call. But you in files that you posted, there are now such hidden calls. It means that error is in your destructor.

ClassA ClassA:: ~ClassA(void)
{
    delete player_;
    delete bullets_;
}

So this code can cause problem. Because if pointers are nullptrs or just some garbage, there will be an access violation. To avoid it, I recommend checking them.

ClassA ClassA:: ~ClassA(void)
{
    if ( player_ )
    {    
        delete player_;
        player_ = nullptr; // or NULL if it's not c++0x
    }
    if ( bullets_ )
    {
        delete bullets_;
        bullets_ = nullptr;
    }
} 

But to make this code really protect, you must
1.Set them to nullptr at constructor
2.Set them to nullptr anywhere else after callin delete on them.

That's it. Write back if it helps.

MarkGrin