Pointers and segfaults

Started by
9 comments, last by MaulingMonkey 17 years, 5 months ago
This one really has me stumped; I have the following class class cClass { public: cClass() { bob = new int;} ~cClass() { delete bob;} int WTF(char *charName) {*bob = 5; return 0;} private: int *bob; }; which will segfault whenever WTF is called. I really cannot understand why...please help!
Advertisement
I saw no errors in the code, and then tried running it, which did not create any segfaults for me. Perhaps the problem lies in where you call the function? Show some relevant code.
The example I gave was like a proof of concept, not my exact code which I provided below:

the actual class (not much in it, I was trying to write it but couldn't get around the segfault :P so I deleted everything till it got so basic and still not functional that I had to turn for help
#pragma onceclass AGE_MD3Manager{	public:		AGE_MD3Manager() { bob = new int;}		~AGE_MD3Manager() { delete bob;}					int loadCharacter(char *charName) {*bob = 5;}	private:		int *bob;};


here is where the class is defined. also note the definition of AGE_Player which calls the loadCharacter function.
#pragma once#include "AGE_Texture.h"#include "AGE_BSP.h"#include "AGE_Player.h"#include "AGE_Camera.h"#include "AGE_MD3.h"struct sInfo{	float gravity;	float terminalVelocity;};class AGE_Engine{public:	AGE_Engine();	~AGE_Engine();	// transfers control to AGE	int go();		// when things go wrong	inline void b0rked() {delete this;}	// processes events	bool pump();	// accessors	inline AGE_Texture	*getTexManager() {return &texHandler;}	inline AGE_MD3Manager *getMD3Manager() {return &md3Handler;};	inline AGE_Camera	*getCamera() {return &cam;}	inline AGE_BSP		*getBSP() {return &bsp;}		sInfo	info;private:	// initialization functions	bool initSDLGL();	// other stuff	AGE_Texture	texHandler;	AGE_MD3Manager md3Handler;	AGE_BSP		bsp;	AGE_Player	player;	AGE_Camera	cam;};extern AGE_Engine *engine;


and the function call is in the constructor of AGE_Player
AGE_Player::AGE_Player(){	acceleration = position = cVectorf(0, 0, 0);	charHandle = engine->getMD3Manager()->loadCharacter("sarge");}


I think this is all the relivant source...if you need anything else let me know.
Allow me to highlight the pointers at work here.

int WTF( char * charName ) { *( this->bob ) = 5; return 0; }

Okay, so we have two failure points. The most likely reasons using a pointer will fail are:

1) Invalid address (commonly NULL, or random garbage if you used an uninitialized pointer)
2) Invalidated object (delete called, and then the pointer accessed. Non-NULL deleted pointers are called "dangling pointers").

Let's first focus on bob. There is one way for bob to be invalid even if this isn't. In C++ Programming, there is something known as the "Law of three":

"If a class needs an explicitly declared copy constructor, copy assignment operator, or destructor, then it usually needs all three."

In this case, only the pointer will be copied if we copy the cClass (since we havn't manually implemented copy/assignment). This will explode:

void example() {    cClass a;    //new scope:    {         cClass b = a; //now shares a's pointer    }    //scope ends, delete b.bob called - but a.bob still points at it    //we have a "dangling pointer".    a.WTF( "..." ); //uses deleted bob, will bork}//scope ends, will call delete a.bob, will also bork (can't delete the object twice)


Moving onto the problems with this, they are many:

void example() {    cClass * bork;    bork->WTF( "..." );    //will bork on the bob line    //(could have borked on the call if WTF was a virtual function)    //(since WTF is non-virtual, accessing bob is the first "actual use" of the this pointer)    //"Access violation at 0x________" (_______ can be/is garbage)    bork = 0; //initialized to NULL    bork->WTF( "..." ); //same problem as above - NULL isn't a "valid" pointer.    //common symptom: "Access violation at 0x00000000" (or similar small value)    bork = new cClass;    delete bork;    bork->WTF( "..." ); //this time, bork is a dangling pointer (deleted but non-NULL)    //common symptom: "Access violation at 0x________" (the blank will have some hard to recognize patterns, but they don't matter)    {        cClass scoped_class;        bork = & scoped_class;    } //scoped_class destroyed    bork->WTF( "..." );    //the same as the previous WTF - still a dangling pointer.    //shows that not all dangling pointers actually involve delete.}


Hope this helps!

EDIT:

charHandle = engine->getMD3Manager()->loadCharacter("sarge"); //*(...->bob) = 5;

Highlighted the failure points :-)
Quote:Original post by MaulingMonkey

charHandle = engine->getMD3Manager()->loadCharacter("sarge"); //*(...->bob) = 5;

Highlighted the failure points :-)


Plus that loadCharacter does not return any value for charHandle to get assigned to that I can see. (I guess that was not included in your post)
I replaced the call to loadCharacter with cout << engine << endl; lo and behold, at that time the engine pointer == 0 :P at what point will the engine pointer be valid? after the constructor for AGE_Engine ?
Quote:Original post by rhollencamp
I replaced the call to loadCharacter with cout << engine << endl; lo and behold, at that time the engine pointer == 0 :P at what point will the engine pointer be valid? after the constructor for AGE_Engine ?


Yes, if you define the contructor that way, which is what you should. As it seems now, though, you have not defined it at all (should not this cause problems at compile time, since the linker does not find any defintions for it?).
Lajnold: The source I pasted was an abridged version of the actual code; I gave you the header but not the implementation.

Now that I know what the problem is, I just made it so AGE_Player isn't initialized until the engine is done initializing.
Thanks guys for your help, I dono if I would have figured that one out on my own! Now that that's out of the way I can go rewrite all the stuff I deleted to try and debug what was going on :P Again thx for the help
This is why version control rules. Or at worst, always make a backup before you start deleting. Saves a lot of wasted time rewriting things :)
Or you could, you know, use asserts to verify the pointers you're working with.

Or for that matter, reconsider whether you really need to allocate memory dynamically, and if so, whether you can do it with a standard library container instead.

BTW, what's AGE? (Hint: namespaces!)

This topic is closed to new replies.

Advertisement