• Advertisement
Sign in to follow this  

Pointers

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

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

Share this post


Link to post
Share on other sites
Advertisement
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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 done
vector<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

Share this post


Link to post
Share on other sites
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 needed
bool 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!

Share this post


Link to post
Share on other sites
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# ...).

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
"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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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".

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Quote:
Original post by Fiddler
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

My personal impression is that C# uses pointer semantics for classes by default, or better, that allocated objects are accessed via pointers, just without the dreaded ->*& notation, hence pass-by-value would be default.

class Foo {
public Foo (string value) {
Value = value;
}
public string Value { get; set; }
}
static void foo (Foo x) {
x = new Foo("kill");
}
static void bar (Foo x) {
x.Value = "overwritten";
}
static void bar () {
Foo x = new Foo("42");
foo(x);
Console.WriteLine(x.Value);
bar(x);
Console.WriteLine(x.Value);
}


If it would indeed be pass-by-reference by default, then the output would be "kill\noverwritten\n", not "42\noverwritten\n". This is the exact same behaviour you get in C++ for pointers:

class Foo {
public:
Foo (std::string const &value) : Value(value) {}
std::string Value;
};
void foo (Foo *foo) {
foo = new Foo("kill");
}
void foo (Foo *foo) {
foo->Value = "overwritten";
}
static void bar () {
Foo x ("42");
foo(&x);
std::cout << x.Value << '\n';
bar(&x);
std::cout << x.Value << '\n';
}


Output: Same as C# code.

Hence, imho, C# classes have pointer semantics by default. And imho2, this is not a good thing. Imho3, it would be best if default would be pass-by-const-reference.

Share this post


Link to post
Share on other sites
@Shinkage: you are correct (read some more on the topic after my last post). I thought VC2008+ was supposed to be pretty standards-compliant out of the box. Sucks that you (still) can't trust this compiler in 2010...

@phresnel: Seems there is some confusion over terminology. C# parameters are *always* pass-by-value, unless you explicitly specify otherwise (via ref or out). Moreover, classes are always accessed via references (see reference types) - in your code, the Foo parameters are references passed by value (which is why changes to Foo are reflected back to the caller). If Foo was a struct, changes wouldn't have been reflected back to the caller (unless the parameter was specified as 'ref').

The fact that C# references work somewhat like C++ pointers does not mean that they *are* pointers. It means that C++ is somewhat of an oddball. C# provides both pointers and references, anyway.

In fact, you could rewrite your C++ code to use references and it would look much closer to the C# version. The main (only?) difference would be that you wouldn't be able to pass null values in C++, while you would be able to do so in C# - and some people actually consider this a major design flaw in .Net (myself included).

Share this post


Link to post
Share on other sites
Quote:
Original post by Fiddler
@phresnel: Seems there is some confusion over terminology. C# parameters are *always* pass-by-value, unless you explicitly specify otherwise (via ref or out).

Quote:
humble me
, or better, that allocated objects are accessed via pointers, just without the dreaded ->*& notation, hence pass-by-value would be default.




Quote:
Moreover, classes are always accessed via references (see reference types) - in your code, the Foo parameters are references passed by value (which is why changes to Foo are reflected back to the caller). If Foo was a struct, changes wouldn't have been reflected back to the caller (unless the parameter was specified as 'ref').

And if you do void foo(Foo x) { x = new Foo(); } then the parameter passed in by the caller won't be hurt, which is exactly as C++ pointers behave. To hurt the callers, one must void foo(ref Foo x) { x = null; } or void foo(Foo* &x) { x = 0; }.

Yes, that is exactly why there is often confusion: On the one hand, you can tweak the members of the passed object, but not the object itself.


Quote:
The fact that C# references work somewhat like C++ pointers does not mean that they *are* pointers.

But they behave a lot like them. The only real difference I see is that C#-references as you describe are distinct from arrays and forbid for pointer-arithmetics. The other, minor difference being that the -> and * notation is hidden for them.


Quote:
It means that C++ is somewhat of an oddball. C# provides both pointers and references, anyway.

Admittedly. C++ reference are slightly different from computer science references. On the other hand, in CS, a reference is often an alias for pointers, so C# is not 100% kosher w.r.t. termination, too.


Quote:
In fact, you could rewrite your C++ code to use references and it would look much closer to the C# version. The main (only?) difference would be that you wouldn't be able to pass null values in C++, while you would be able to do so in C# - and some people actually consider this a major design flaw in .Net (myself included).

That is wrong. The main difference would be that the programs no longer behave the same (apart from the mem-leak intentionally left back for sake of example). If I'd use references in the C++ code,

class Foo {
public:
Foo (std::string const &value) : Value(value) {}
std::string Value;
};
void foo (Foo* &foo) {
foo = new Foo("kill");
}
void foo (Foo* &foo) {
foo->Value = "overwritten";
}
static void bar () {
Foo x ("42");
foo(&x);
std::cout << x.Value << '\n';
bar(&x);
std::cout << x.Value << '\n';
}


, the output would become "kill\noverwritten\n" and is no longer identical to the C# version.

Or, if I skip the pointers,

class Foo {
public:
Foo (std::string const &value) : Value(value) {}
std::string Value;
};
void foo (Foo &foo) {
// foo = new Foo("kill"); not possible
}
void foo (Foo &foo) {
foo->Value = "overwritten";
}
static void bar () {
Foo x ("42");
foo(&x);
std::cout << x.Value << '\n';
bar(&x);
std::cout << x.Value << '\n';
}


output would be the same for this example, but the programs are as well no longer equal.

Share this post


Link to post
Share on other sites
Quote:
Original post by phresnel
If I'd use references in the C++ code,

*** Source Snippet Removed ***

, the output would become "kill\noverwritten\n" and is no longer identical to the C# version.


That's because you are using pass-by-reference in C++ but pass-by-value in C#.

Quote:

Or, if I skip the pointers,

*** Source Snippet Removed ***

output would be the same for this example, but the programs are as well no longer equal.


That's because C++ references don't allow reseating.

C# and C++ have two slightly different worldviews regarding references and pointers. This still doesn't mean that C# references are C++ pointers, though. They are not 100% equivalent to C++ references either, which is why C++/CLI treats .Net references (^, called 'handles') as a completely different type than C++ references (&) and pointers (*).

Share this post


Link to post
Share on other sites
Quote:
Original post by Fiddler
Quote:
Original post by phresnel
If I'd use references in the C++ code,

*** Source Snippet Removed ***

, the output would become "kill\noverwritten\n" and is no longer identical to the C# version.


That's because you are using pass-by-reference in C++ but pass-by-value in C#.

No. Or better: Exactly that was the point. In the original example, I was passing-by-value a pointer. Which yielded the same behaviour as the initial C# example with default calling convention.

Which is also why I said
Quote:
hence pass-by-value would be default
... in C#.



Quote:
They are not 100% equivalent to C++ references either

And I did not claim that. But for a large part, if you skip the pointer/array-analogy and pointer-arithmetics, they behave similar. As shown in my initial example.


But at one thing I agree with you: The terminology of C# and C++ is incompatible, both are not perfect w.r.t. CS.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement