Sign in to follow this  

simple question about pointers to classes

This topic is 3492 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

so I have a big class for my entire game called GAME. If I declare a pointer to a GAME object like this: GAME* mygame; When I try to use it like so: mygame->Run(); This crashes my program. But if I declare it as a normal variable (ie not a pointer) and access it with the . operator it works fine. I've heard its a waste of memory and I'm better off using pointers but that crashes my program. Anyone know what is best and why?

Share this post


Link to post
Share on other sites
When you create a pointer to GAME you must then create a GAME object for it to point to, like this:
GAME* myGame = new GAME;
And don't forget to delete it when you have finished:
delete myGame;

You might want to google a tutorial on pointers and 'new'.

Share this post


Link to post
Share on other sites
Depends on the situation, but from what you've told us, it probably won't make much of a difference here. That GAME instance takes the same amount of memory, whether it's allocated on the stack ('normal') or on the heap (new / delete).


Oh, and just a tip: uppercase names are commonly used for macro's and the like. Camelcase would be better: Game, ClassName, etc.

Share this post


Link to post
Share on other sites
Yes, if your game object is very large, especially if it's larger than your stack size (unlikely, but still possible).

Yes, if you don't understand how "normal" variables (i.e. stack variables) work (for example, if you try to generate your Game object in a function).

No in every other case. In many situations it is better to use "normal" (stack) variables.


Stack variables are generated on the stack, as the name suggests. Stack size is limited, usually a megabyte or two. Allocating and freeing objects is very fast (3-4 CPU cycles) as opposed to operator new which usually takes a few hundred cycles, but doesn't have any guarantees (it might as well take 1/10 second).

Stack variables are automatically deleted when they go out of scope (function, or {} block). This is a good thing because you don't need to care about it and because it's exception-safe. It also means, however, that function B cannot see a variable that was created in function A, it simply doesn't exist there. This is a common mistake every beginner makes at some point.

If you need larger than normal alignment (for example when programming with SSE), then you can __declspec a stack variable accordingly, and it will work "magically". The compiler will make sure it does. When using a pointer and operator new, you are only guaranteed correct alignment for all built-in types, everything that goes beyond that is your responsibility.

A stack variable or a reference to it cannot be a null pointer (or invalid pointer)1, so foo.bar is guaranteed to never crash. Never.
A pointer, on the other hand, might be invalid (or null, which is invalid too) if you're doing something wrong, so there is no such guarantee. If you are not diligent, you may forget to delete a pointer, or delete a pointer twice, which can be a desaster. That can't happen with a stack variable, because it's automatic.

Other than that, accessing via . and -> is the same thing, no difference, and no penalties.


1Ok, ok,... with enough malevolence, you can manage to get that to happen too, but normally it will not happen. :-)

Share this post


Link to post
Share on other sites
There are more advantages to using heap allocation (new and delete). The main reason to ever use it is to allocate an unknown amount of memory. For example:

unsigned int n;
cin >> n; //get a number

float badArray[n]; //ERROR! Will not compile!
float *goodArray = new float[n]; //will work just fine
delete[] goodArray; //never forget to delete memory on the heap



Also, while heap allocation is slower than stack allocation, the difference is not significant for 99% of the applications you will ever code. Besides, there is a workaround; the code I showed above will only do one allocation for n amount of objects. If you need two hundred objects, allocating them all at once with a single call to new will make the speed difference between heap and stack insignificant for this purpose.

Share this post


Link to post
Share on other sites
Quote:
Original post by always_learning
Good answers, thanks everyone. Ratings++

Also I've heard that when passing a structure to a function you usually want to pass a pointer. Is that like a general rule of thumb and does it improve performance?

Yes, but there are exceptions. There are four common types of arguments that a function can accept. Below is a function that accepts one argument of each type:


void Demo(int value, int *pointer, int &reference, const int &secondReference)
{
//do stuff
}




The first argument, "value", is declared the way most function arguments in C++ are declared. These arguments are passed by value, which means that when you call the function, C++ will create a copy of whatever instance you passed as the argument and then act on that in the function. Obviously, big objects (like structs and classes can be) are therefore bad to pass as regular arguments.

Also, since the variable "value" is just a copy of the variable you passed to the function, you cannot affect the original variable through "value". This obviously has both benefits and drawbacks.

The second argument is obviously a pointer. This means several things:
* The data the pointer points to is never copied, only the pointer itself.
* You can change the contents of the original data the pointer points to.
* The syntax for passing arguments to the function changes.
* You can delete what the pointer points to, which is unsafe[1].

The third argument is a reference. A reference is similar to a pointer, but it acts like a variable. The following is relevant in regards to references:
* The data the reference references is never copied, only the reference itself.
* You can change the contents of the original data, just like a pointer.
* The syntax for passing arguments to the function is identical to regular values.
* You can NOT delete what the reference points to, nor can you change the address it points to. This makes it significantly safer than pointers.

The last argument is a const reference. The difference between this argument and the regular reference is that you cannot change the contents of the data referenced. It therefore becomes pretty much exactly like a regular value argument, except that the data is never copied. This makes the const reference highly attractive to use for arguments that are large datatypes; using const references is strongly encouraged.

[1]A word on deleting pointers: if you make a habit out of setting all your unallocated pointers to 0 (or create a wrapper class that does it for you), you can always delete the pointers safely. This is because it is safe and correct to delete a null pointer; it doesn't do anything, but it also doesn't crash your program. Another advantage is that it becomes easy to check if the pointer is pointing to something by using if(ptr) DoStuff();.

[Edited by - Hnefi on May 26, 2008 6:29:43 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by samoth
A stack variable or a reference to it cannot be a null pointer (or invalid pointer)1, so foo.bar is guaranteed to never crash. Never.

1Ok, ok,... with enough malevolence, you can manage to get that to happen too, but normally it will not happen. :-)


Well, as with everything else in C++, it's more complicated than that. What is certain, though, is that foo.bar will never crash (it is, however, perfectly possible for a program to create undefined behavior before that statement, and then appear to crash when executing foo.bar, but the crash is caused by the original undefined behavior and not the statement itself).

Share this post


Link to post
Share on other sites

This topic is 3492 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.

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