Skip to main content
GameDev.net gamedev.net
🔒 Locked

Pointers

Started by Steve25 Jul 17, 2010 at 1:04 PM 24 replies 3.5k views
Original Post
Steve25
Steve25
I realise this is probably going to seem like a very newbie question but I can't seem to get my head around Pointers in C++.

I'm mostly a C# and Java programmer and mostly to create games I've been using the XNA Framework with the C# Programming language. I've only really done simple 2D games as of yet but they're still great fun to make and play. However I've realised that if I want to be serious about Games development C++ is the way to go.

I've done a lot of C++ in the past but lately I've been trying to learn Pointers. I can create Pointers and make them work etc. but to be honest I don't really see the point in Pointers. The only Pointers I've ever really found use for is the this keyword and passing data by reference in methods.

So could anyone perhaps try to explain to me when you would use Pointers, why you would use them instead of ordinary variables and how they are useful in games and other software. Thanks
Ripiz
Ripiz
For example you have one huge 3D Model which takes 100 MB RAMs. Without pointers your computer will copy it to use in some function, that function will copy it again to use in another function, and it'll keep going, even if either of functions edit Model, first Model you had won't change.. Pointers allow to read and modify original Model, without copying it.
rip-off
rip-off
Pointers have a couple of uses:

1) Avoid copies.

When you pass or return a complex type to a function, you can pass it by value or by reference. By value will create a copy, which is often unnecessary. You can use a pointer to pass it by reference, but in C++ you would use a C++ reference, like so:
void foo(const ComplexType &instance){   // Look ma, no copies!}

You might need to use pointers for this when passing to external code, as mentioned in #4

2) Optional Aguments

If you want to have an optional argument, you could use a pointer. Then you can either pass NULL, the address of a local variable or the value of a heap pointer. In modern C++, you could use boost::optional<> for this. You might need to use pointers for this when passing to external code, as mentioned in #4

3) Implementing new data structures

If you need to implement a new data structure (check that it isn't already available in the standard library first!) then you will often find yourself using raw pointers.

4) Large arrays

The stack is limited. On Windows, you have about 1MB of stack, and you will want to save most of that for function calls. So if you have any large pieces of data, you have to dynamically allocate it, and that involves pointers if done manually. However, modern C++ users would use std::vector<> instead of managing raw arrays.

5) Legacy Code / Interfacing with an API

There is lots of pre-existing code out there that uses pointers. As such, you have no choice but to use the existing functions. A very frequent example is C strings, or null terminated character arrays. Most low level APIs will require you to pass C strings as a pointer.

APIs are often written in C, and will expose all complex types via pointers. These can be wrapped with RAII classes to make them safer to use, but you still need to deal with pointers when wrapping them.
Steve25
Steve25
Quote:
Original post by Ripiz
For example you have one huge 3D Model which takes 100 MB RAMs. Without pointers your computer will copy it to use in some function, that function will copy it again to use in another function, and it'll keep going, even if either of functions edit Model, first Model you had won't change.. Pointers allow to read and modify original Model, without copying it.


If you pass data to a function by value yes it makes a copy but that copy is erased when the method expires so it's not really a problem. For that reason I don't really see how Pointers would be beneficial here.

rip-off: Number 1 I see the use for, but of course you're using a reference there which I guess is a type of pointer. However, for point number 2 I guess you could do it that way but isn't that what method overloading is for? Number 3, isn't that very unlikely unless of course you mean creating your own types via classes? Not really come across the one for number 4 but I guess that's similar to using Lists in C#. And number 5 is the only time I've really used them because I've had to.
oler1s
oler1s
Quote:
If you pass data to a function by value yes it makes a copy but that copy is erased when the method expires so it's not really a problem.
Wait, what? 1) Time is required to make that copy and 2) You need memory for that unnecessary duplicate

That's not a problem at all? That's an enormous performance penalty.

Want to understand why pointers exist? Create a linked list. Once you have done that, you'll get it.
Ripiz
Ripiz
Quote:
Original post by Steve25
If you pass data to a function by value yes it makes a copy but that copy is erased when the method expires so it's not really a problem. For that reason I don't really see how Pointers would be beneficial here.


Lets say your Model is 100 MB in size

vector<Player> players;Model model("my 100 mb model.x");for(int i = 0; i < 10; i++){   players.push_back(Player(i * 32, i * 32, model)); //you just took 100 mb, and again, and again, and again...}//looks like 1 gb RAMs gone//also spent like 10 seconds copying data//Instead you could have donevector<Player> players;Model *model = new Model("my 100 mb model.x");for(int i = 0; i < 10; i++){   players.push_back(Player(i * 32, i * 32, model));}//only 100mb + 10*4 bytes for pointers, and like 0.000001 second to set those pointers



Quote:
Original post by Steve25
number 2 I guess you could do it that way but isn't that what method overloading is for?

Without pointers one method will be able to return 1 value, with pointers you can modify as many values as you wish

Quote:
Original post by Steve25
Number 3, isn't that very unlikely unless of course you mean creating your own types via classes?

I'm really sorry for you if you won't use classes or structures in your code
rip-off
rip-off
Quote:
Original post by Steve25
If you pass data to a function by value yes it makes a copy but that copy is erased when the method expires so it's not really a problem. For that reason I don't really see how Pointers would be beneficial here.

They give you the option of avoiding the performance hit. As a C#/Java programmer, you know that objects are passed by reference in these language. This is similar to passing a pointer in C++. Passing a value in C++ is like a struct in C#, or using a deep clone() method for class types in Java/C#. You can see that this is unnecessary in many cases.

There are also uncopyable classes to consider. Types that represent external entities are frequently noncopyable. So you can't copy standard file types, most libraries won't let you copy a socket and you often won't find a copyable texture type. To pass these to functions, you must use a reference or a pointer.
Quote:

Number 1 I see the use for, but of course you're using a reference there which I guess is a type of pointer.

It is best if you try separate the ideas of pointers and C++ references. Semantically, a C++ reference is well defined (it is not-null, not-reseatable and not an array). A C++ pointer could be NULL, could point to an arbitrary element of an array, or could be uninitialised if you aren't careful.
Quote:

However, for point number 2 I guess you could do it that way but isn't that what method overloading is for?

Yes. But consider the case where the method body is complex. You don't want to have two versions of non-trivial code. Instead you write the same function, and just add null checks before using the optional parameter. Or consider providing an optional parameter to "write-back" through. An example:
/*   Returns true if the two lines intersect.   Writes the intersection point to "out" if out is not null.*/bool intersection(const Line &one, const Line &two, Point *out){   // ...}// Convenience function for when the intersection point is not neededbool intersection(const Line &one, const Line &two){   return intersection(one, two, NULL);}

Note how we only had to write the logic once, which is what you should strive for.
Quote:

Number 3, isn't that very unlikely unless of course you mean creating your own types via classes?

It isn't common, but the C++ standard library does not contain implementations of lots of the spatial partioning structures you are likely to need as a game programmer. Either you, or the person who writes the library you choose to use, will need pointers for this.
Quote:

Not really come across the one for number 4 but I guess that's similar to using Lists in C#.

Exactly. In C++ you would generally use std::vector<> where C# uses List. But std::vector<> must use pointers, as this is the only way to handle dynamic allocation in C++.
Quote:

And number 5 is the only time I've really used them because I've had to.

This isn't likely to change. Library writers generally aim for C or simple C++. This simplifies things like building the library as a DLL. This leaky abstraction is then pushed onto you in the difficulty in interfacing with the library.

Also, library writes hate additional dependencies. You won't see too many libraries using boost, many will even avoid the standard library in case you aren't using it yourself. This might just be the fact that I've mainly used game libraries, which tend to be extreme about this sort of things. Even in the standard library the file interface uses C strings, to avoid the dependency on std::string!
Xai
Xai
One thing I don't think has been pointed out is that the OP is used to Java and C#. So all of the arguments about by-value versus by-ref are actually off the mark. The OP is used to using pointers each and every day of his programming life, he just didn't realized it. Reference in Java and C# ARE POINTERS, plain and simple. The only difference is the language has limited what you are allowed to do with them and made the syntax the same as when you are not using pointers.

In the original C-like language there are 2 types of variables, variables that ARE the address of a value and variables that are a value which is the address of another value. The first are things like int and char. When you declare "int a;" the compiler sets aside space for an int (4 bytes usually) and each place in the program where it needs to use a it compiles in the address it has set aside. When you declare "int *b;" the compiler creates space for a pointer (also often 4 bytes) and each time you refer to "b" the compiler compiles in the address it has set aside for this pointer. But with pointers you can set the pointer's value equal to the address of other values, so you can write code which works on different values, without realizing it. For instance if you set aside 100 ints in a row like "int c[100];", then you can do things like "a = &c[10]" to say "set a to the address of element 11 in the array" ... which you could then set, modify, compare or whatever. Perhaps you are looping through the array sorting it.

Or imagine a game with the player and a list of 100 monsters. you might find it useful to have a monster pointer to store the player's current target ... which would be a pointer to 1 of the 100 monsters within the list of monsters. Etc.

Now everything I've said makes sense to you and seems silly, because you already use pointers all the time, you just call them "references". A reference is a pointer. In fact before C++ added the special "reference" syntax, everyone who wrote in C and C++ used the term reference to mean pointer. passing a pointer was called "pass by reference". Then people like C++, Java and other languages decided they wanted to make it easier for the compiler to keep programmers from doing risky and sometimes incorrect things with pointers, so they can up with a new type of variable, a limited pointer, and they called it a reference. When ALL of these languages first implemented these references, it was exactly the same opcodes that they used for pointers ... the only difference was that they did more compile time checking to make sure the programmer was using them according to the limited contract they agreed to, and they didn't provide any means for the programmer to get the actual numeric address of the pointer ... therefore the programmer couldn't do things like add 2 references together to get some random third address and then try to use that address as if it made sense.

In C# when you write:

// this C#Control b = new Button();b.Text = "Push Me";// is the same as THIS C++Control *b = new Button();b->Text = "Push Me";// and is NOT the same as this C++ (which makes no sense)Control b = new Button();b.Text = "Push Me";


So when you write Java and C# using classes, you are using pointers, so when you ask "WHY would anyone use pointers", you are asking the wrong question. You really mean something more like "Why or when should I use C++ pointers instead of C++ references".

To which there are many valid answers ... and the short answer is, in C++ you would use reference ANY AND EVERYWHERE you possibly can ... but there are many many places that references in C++ cannot suffice (because the reference in C++ is actually less powerful than a reference in Java or C# ...).
Fiddler
Fiddler
Quote:
Original post by Xai
In C# when you write:

// this C#Control b = new Button();b.Text = "Push Me";// is the same as THIS C++Control *b = new Button();b->Text = "Push Me";// and is NOT the same as this C++ (which makes no sense)Control b = new Button();b.Text = "Push Me";



Actually, that's not entirely correct. The equivalent C++ version would use references:
Control& b = Control();b.Text = "Push me";


C# references are not equivalent to C++ pointers. C# distinguishes between references and pointers just like C++ does.

The main difference between C# refs and C++ refs is that C# classes use reference semantics by default, whereas C++ classes use value semantics by default (structs use value semantics in both). C# pointers are a slightly more limited version of C++ pointers.

[Edited by - Fiddler on July 17, 2010 7:07:25 PM]
[OpenTK: C# OpenGL 4.4, OpenGL ES 3.0 and OpenAL 1.1. Now with Linux/KMS support!]
Steve25
Steve25
Thanks for all of your replies I appreciate the help.

I see now that where I've been writing software in C# and Java I have been using Pointers, but not realised it. It's been there working behind the scenes so the developers of that language don't need to worry about it. The ref keyword in C# is basically a form of reference but in a much simpler form.

Before I thought you should only use Pointers where you really have to, where normal variables just wouldn't work but from reading your comments that doesn't appear to be the case.

Ripiz: Not sure I understand, you're using the same model variable not ten different ones?

rip-off: The optional argument in a method that you explained makes sense to me now thank you. Most C++ primers will explain to use methods will standard variables in its parameters but do you think you should always use references?

Xai: If you are only holding that one control then why do you have to use a Pointer?
GregMichael
GregMichael
"Want to understand why pointers exist? Create a linked list. Once you have done that, you'll get it."

Also, learn some assembler...then you'll get pointers and a whole bunch of other useful stuff...like there are goto's in (asm) code...lot's of them in fact.
nobodynews
nobodynews
Quote:
Original post by Fiddler
Actually, that's not entirely correct. The equivalent C++ version would use references:
Control& b = Control();b.Text = "Push me";
I'm not sure that's equivelent for two reasons. First, the C# version has b (a Control) point to a Button (presumably Button is derived from Control). Second, the C# version could have b refer to something else in the future like another Button or to another object derived from Control like, say, a ComboBox. In fact, I'm not sure whether you can even create a non-const reference to a temporary like that.
C++: A Dialog | C++0x Features: Part1 (lambdas, auto, static_assert) , Part 2 (rvalue references) ,
DevFred
DevFred
You can't.
Fiddler
Fiddler
Quote:
Original post by nobodynews
I'm not sure that's equivelent for two reasons. First, the C# version has b (a Control) point to a Button (presumably Button is derived from Control). Second, the C# version could have b refer to something else in the future like another Button or to another object derived from Control like, say, a ComboBox. In fact, I'm not sure whether you can even create a non-const reference to a temporary like that.


Quote:
Original post by DevFred
You can't.


VS2010 disagrees. The following code compiles fine:

class Control{public:	char *Text;};class Button : public Control { };class ComboBox : public Control { };int main(int argc, char *argv[]){	Control& b = Button();	b.Text = "Push me";	b = ComboBox();	b.Text = "Hey, would you look at this!";	return 0;}


I can't be bothered to the C++ spec on this but I'm inclined to trust the compiler.
[OpenTK: C# OpenGL 4.4, OpenGL ES 3.0 and OpenAL 1.1. Now with Linux/KMS support!]
rip-off
rip-off
Quote:
Original post by GregMichael
"Want to understand why pointers exist? Create a linked list. Once you have done that, you'll get it."

Also, learn some assembler...then you'll get pointers and a whole bunch of other useful stuff...like there are goto's in (asm) code...lot's of them in fact.

Yes, but gotos are almost never useful in higher level languages - without any loss of expressivity. I would argue that C++ pointers are similar to gotos, they can express lots of different things and this makes it harder to read the code. Is a goto supposed to represent an unconditional jump, a condition, a loop? Likewise, is a pointer being used as a reference, to allow NULLs, for array iteration, to manipulate raw memory? You can design a language that separates the above concepts, becoming more expressive for no loss in functionality. So if someone really needs a opt "raw ref array byte" type, they can use it, but 99.999% of the time they can use something which is closer to their intent. Programming is in many ways all about expressing intent.
Quote:

I can't be bothered to the C++ spec on this but I'm inclined to trust the compiler.

It doesn't compile in VC2008 if you disable language extensions.

Fiddler
Fiddler
Quote:
Original post by rip-off
Quote:

I can't be bothered to the C++ spec on this but I'm inclined to trust the compiler.

It doesn't compile in VC2008 if you disable language extensions.


Bleh, doesn't compile in g++ either. So much for trust in compilers.
[OpenTK: C# OpenGL 4.4, OpenGL ES 3.0 and OpenAL 1.1. Now with Linux/KMS support!]
Steve25
Steve25
I'll try and find more examples and get used to actually using Pointers. I get the use in Pointers now and how they are beneficial but I still don't know where it's best to use them. I mean if I was writing a program I wouldn't think I need a Pointer here because I'm not sure yet. Thanks for all your help
rip-off
rip-off
With C++, the best way to treat pointers is to try anything else, and only fall back to using pointers when all other solutions are exhausted [grin]

BTW, you can call them "pointers", it is unnecessary to capatialise the "P".
Steve25
Steve25
Quote:
Original post by rip-off
With C++, the best way to treat pointers is to try anything else, and only fall back to using pointers when all other solutions are exhausted [grin]

BTW, you can call them "pointers", it is unnecessary to capatialise the "P".


I'll give it a shot :) thanks for your help
Shinkage
Shinkage
Quote:
Original post by Fiddler
Bleh, doesn't compile in g++ either. So much for trust in compilers.


There are several things wrong (or at least dangerous) with that piece of code, and even if it DOES compile, I can almost guarantee it's not doing what you think it's doing. First off, references can not be reseated. So when you call this line:
b = ComboBox();
What it's NOT doing is setting b equal to a new ComboBox. What it IS doing, is calling the implicitly generated base class assignment operator which, in my humble opinion, can't POSSIBLY be the intended behavior. Hide the base class' assignment operator and you'll find the code no longer compiles.

In short, the following...
Quote:
Original post by Fiddler
Actually, that's not entirely correct. The equivalent C++ version would use references:
Control& b = Control();b.Text = "Push me";

...is quite incorrect because, again, references can not be reseated. Another way of putting it is that while pointers refer to another piece of data, references ARE that piece of data. For all intents and purposes, once a reference is seated, it becomes the variable it refers to in a, how to put it, very... ontological sense :) Xai was definitely right in his claim that what C# and Java are doing "under the hood" is using (smart/GC'd) pointers, not C++-style references.

EDIT: P.S. Visual Studio will happily compile scores of things that are completely non-standard C++. If you're going to be trusting a compiler to indicate whether something is proper C++, Visual C++ should be your absolute last choice, considering it's rather infamous for defaulting to very non-standard behavior.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.