PDA

View Full Version : Beginner C++ question: Pointers vs References




ifjake
Jun 13, 2006, 04:50 PM
I've been reading through a few C++ articals and tutorials and I've been wondering: what is the difference between pointers and references?



CarbonMike
Jun 13, 2006, 06:08 PM
Quick and dirty answer:

Pointers are addresses, while references are handy substitutes. A reference lets you make function calls (for example) using non-pointer semantics while retaining pointer-like behavior.

Slower and cleaner answer:

Say you wrote a function called changeValue() which takes an Integer parameter. The function will call appropriate get/set methods on the Integer passed as a parameter in order to double its value. If you then write

Integer myInteger(5);
changeValue(myInteger);
cout << myInteger.getValue();

you'd see 5, not 10, on the console out because of C++'s default pass-by-value semantics. A copy of myInteger, not the original, is what actually gets passed to changeValue(). The unwary programmer thinks he/she drank a bad can of Red Bull. :eek:

To avoid this problem, you could rewrite the changeValue function to take a pointer instead:

void changeValue(Integer* anInteger){ ... }

but then you'd have to use pointer semantics in the func call:

Integer myInteger(5);
changeValue(&myInteger); // remember address-of?
cout << myInteger.getValue();

in order to get the correct behavior.

C++ references let you get the behavior you want without pointer semantics; rewrite the function to take a reference to an Integer

void changeValue(Integer& anInteger){ ... } // (it sucks that the reference declarator is the same as the address-of operator; very confusing IMO)

and now you can make the call as normal:

Integer myInteger(5);
changeValue(myInteger);
cout << myInteger.getValue();

and see 10 on the console out, not 5. You get to use pass-by-value semantics while getting pass-by-reference behavior out of the system.
This turns out to be very useful when doing certain types of things in C++.

Hope this helps!

carbonmike

almightyshoe
Jun 13, 2006, 06:09 PM
pointer - an address of an object.


reference - another name for an object. Access to an object via a reference
is like manipulating the object itself. References are typically implemented
as pointers in the underlying generated code.

http://www.glenmccl.com/glos.htm


*waddle waddle*

ifjake
Jun 13, 2006, 10:25 PM
Hey thanks guys.

(it sucks that the reference declarator is the same as the address-of operator; very confusing IMO)

Yeah I think this is where the confusion started.

References are typically implemented as pointers in the underlying generated code.

So this means the compiler generates the same code for references and pointers? What's the advantage of using one over the other? I suppose there is pointer arithmetic (maybe?). I took a C++ course in high school like 4 years ago, and we pretty much stopped right before pointers, so I'm in the process of figuring it out for the first time. There are a few things we didn't even address, like class constructors (which seem like such a cool thing to me). I'm not sure how I got a 5 on the AP exam. It must have been pretty basic. ahem.

BigMäc
Jun 14, 2006, 01:18 AM
This helped me to understand it:

http://www.parashift.com/c++-faq-lite/references.html#faq-8.1

Soulstorm
Jun 14, 2006, 01:40 AM
a guy at the programmingforums.com has added this (http://www.daweidesigns.com/cgi-bin/pointers.php) article to his website, I think it would prove helpful to you.

almightyshoe
Jun 14, 2006, 01:52 AM
I don't actually dabble in C++, C being my bread and butter. Only major difference is we play with structures rather than classes, and I don't like waiting a week and a half to compile a program that prints anagrams.

CarbonMike
Jun 14, 2006, 02:42 AM
Hey thanks guys.

So this means the compiler generates the same code for references and pointers? What's the advantage of using one over the other? I suppose there is pointer arithmetic (maybe?)..


Absolutely not! This is what's important to know about references; they're not pointers as far as the C++ type system is concerned, no matter how the compiler does things behind the scenes. There are three very important restrictions that references impose on you:

You cannot do pointer arithmetic on a reference
Unlike a pointer, you can't dereference a reference
You can't make a reference point to anything else once you've created one

Now what's the advantage of using one over the other? Again, it's all about the call semantics. If I write a function which needs to modify the thing being passed (rather than a copy of it) and I DON'T want to use pointer semantics, it's reference time.

The best example of why this is useful is operator overloading. In fact, I'd hazard a guess that references were a side effect of another language feature.

I wasn't in the room when they had the meeting, but it's probable that once Bjarne & Co. decided to have operator overloading as a feature of C++, they had no choice but to add references to the language as well. Think about it: an overloaded operator is a function which sometimes has to do something to the actual thing(s) you pass, but an overloaded operator only makes sense lexically if you don't have to do anything weird to the passed parameters (like use the address-of operator). Right? The code

Integer myInt(5);
myInt++;

makes a kind of intuitive sense if you know about overloaded operators. But if you had to write

&myInt++;

you'd have a serious ambiguity problem. What would that code mean?
Should you increment the address of myInt, or...? You get the idea. If you look at any overloaded operator that's properly written, you'll see that they're always written to take a reference to a type.


carbonmike

MarkCollette
Jun 15, 2006, 06:09 PM
References are pointers with the syntax of the refered type. It's syntactic sugar to make some code look prettier.

You cannot do pointer arithmetic on a reference
Unlike a pointer, you can't dereference a reference
You can't make a reference point to anything else once you've created one


Of course you can dereference a reference and do pointer arithmetic with it, because it uses the same syntax as the base type (int in my example).

int x = 0;
int& y = x;
int* ptr = (int*) (&y);


And yes you can reuse references, it's just a really bad idea.

class X { ... };
X x;
X& y = x;
X& z;
z = x;

X a;
y = a;
z = a;


I think (you should check) that z will now point to a, whereas y will have invoked x's assignment operator with a as the parameter. Wierdness like that made me change a bunch of code from references to pointers, so that noob programmers couldn't accidently mess things up.



Now what's the advantage of using one over the other? Again, it's all about the call semantics. If I write a function which needs to modify the thing being passed (rather than a copy of it) and I DON'T want to use pointer semantics, it's reference time.

The best example of why this is useful is operator overloading. In fact, I'd hazard a guess that references were a side effect of another language feature.

Exactly. References were added to make things easier for people who just can't wrap their heads around pointer syntax. In the end, people want the Fortran and VB idea where all variables look the same, but you say if it's an "input" variable, or an "input and output" variable.

The problem is that there are some freaky corner cases that most people will just mess up.

CarbonMike
Jun 16, 2006, 09:31 AM
Of course you can dereference a reference and do pointer arithmetic with it, because it uses the same syntax as the base type (int in my example).


Sorry, I should have been more clear here. Unlike a pointer, whose address you can actually refer to, you can never get the address of the reference itself; the language is basically always hiding the underlying pointer from you.


And yes you can reuse references, it's just a really bad idea.



This is just about true -- although your sample code cited below certainly will not compile, because you're creating a reference (X& z) without assigning it to anything. Reuse in that sense is verboten.

class X { ... };
X x;
X& y = x;
X& z;
z = x;

X a;
y = a;
z = a;


But you're right, and I was wrong, concerning the ability to make a reference point to something else once it's been assigned. I also agree that it's a terrible idea!



Exactly. References were added to make things easier for people who just can't wrap their heads around pointer syntax.


I couldn't disagree more on this point. I think references are a part of C++ because you can't do syntactically credible operator overloading without them, given the function call semantics of the language. Hell, if it's one thing C++ *doesn't* accomodate, it's people who can't wrap their heads around tricky syntax!


carbonmike

MarkCollette
Jun 16, 2006, 02:03 PM
This is just about true -- although your sample code cited below certainly will not compile, because you're creating a reference (X& z) without assigning it to anything. Reuse in that sense is verboten.

class X { ... };
X x;
X& y = x;
X& z;
z = x;

X a;
y = a;
z = a;


But you're right, and I was wrong, concerning the ability to make a reference point to something else once it's been assigned. I also agree that it's a terrible idea!

Perhaps newer compilers won't allow "X& z;" but two years ago when I was doing C++ programming this was a real issue. Part of the problem is that it's sortof a C versus C++ style issue of where you declare your variables, at the top of the function, or right where they're needed.


I couldn't disagree more on this point. I think references are a part of C++ because you can't do syntactically credible operator overloading without them, given the function call semantics of the language. Hell, if it's one thing C++ *doesn't* accomodate, it's people who can't wrap their heads around tricky syntax!

//Calling a method on an object:
X x;
x.method();

// Calling a method on a reference:
X y;
X& x = y;
x.method();

// Calling a method on a pointer using pointer specific syntax:
X y;
X* x = &y;
x->method();

// Calling a method on a pointer using object-ish syntax:
X y;
X* x = &y;
(*x).method();


I think you're exactly agreeing with my point that references exist so C++ programmers won't have to deal with the complexities of pointer syntax.

And C++ is all about allowing you to type simple syntax, while in the end still having to comprehend the vagaries of what's really hapenning.

As in, they made something look pretty, but in the end didn't really make it easier.

Gil Bates
Jun 16, 2006, 08:41 PM
Hi All,

I've never posted here before, but hopefully my post shows up ok.

Although I'm pretty sure references are implemented using pointers, there are some significant differences. Sometimes, you need them to define a function without using a strange syntax or significant overhead. For example, to define an assignment operator or a copy constructor, we usually do:


MyClass & MyClass::operator=(const MyClass & original);

MyClass::MyClass(const MyClass & original);


Without a reference, you'll either need to create a temprary:


MyClass MyClass::operator=(const MyClass original);

MyClass a, b;
a = b; // this could (should?) created a temporary for "original" from "b".


Or use a wierd syntax like:


MyClass MyClass::operator=(const MyClass * original);

MyClass a, b;
a = &b;


References need to be initialized immediately. So, in your example, "X& z;" should be an error. Even if your compiler doesn't give you an error, the next line "z = x" can crash because "z" refers nothing (and the pointer that implements it points nowhere).



And yes you can reuse references, it's just a really bad idea.

class X { ... };
X x;
X& y = x;
X& z; // error!
z = x; // crash!

X a;
y = a; // copy a into x. y still refers x.
z = a; // crash, again!


I think (you should check) that z will now point to a, whereas y will have invoked x's assignment operator with a as the parameter. Wierdness like that made me change a bunch of code from references to pointers, so that noob programmers couldn't accidently mess things up.



Also, references cannot be "reused". There is no way to do it. The above "y" always referes "x" (and "z" always refers nothing if you can get it to compile :)).

Hope this helps,

Gil

MarkCollette
Jun 19, 2006, 12:33 PM
References need to be initialized immediately. So, in your example, "X& z;" should be an error. Even if your compiler doesn't give you an error, the next line "z = x" can crash because "z" refers nothing (and the pointer that implements it points nowhere).

Also, references cannot be "reused". There is no way to do it. The above "y" always referes "x" (and "z" always refers nothing if you can get it to compile :)).

Hope this helps,

Gil

That example I gave for the references, is not legal, but was allowed by Visual C++ 5 and 6, Sun's C++ compiler, and DEC Alpha's C++ compiler. And none of them crashed. But yes, the point I was trying to make was that once assigned, subsequent "assignments" would simply be operator= calls on the first object.

And even with regular objects (not references), there's the distinction between:

X a;
X b = a; // Same as X b( a );
X c;
c = a; // Different operator

So the real crux of it is that because operator overloading obfuscates what's really going on, and references syntactically behave like regular objects, then they inherit non-obvious behaviors. Whereas pointers always behave the same, and always have obvious consequences.

That said, the whole point of operator overloading is to munge with standard behaviours, to I'm not saying it's bad, just that there are places where I feel it's better to use pointers instead of references.

Gil Bates
Jun 19, 2006, 05:01 PM
That example I gave for the references, is not legal, but was allowed by Visual C++ 5 and 6, Sun's C++ compiler, and DEC Alpha's C++ compiler. And none of them crashed. But yes, the point I was trying to make was that once assigned, subsequent "assignments" would simply be operator= calls on the first object.


Sorry to hear your code didn't even crash. If it did, it would've been much easier to find the bug :). I'm a bit surprised none of your compilers didn't give you an error. If I'm not mistaken, references were alreay in in the 1st edition of Stroustrup's book back in the late 80s.

I just felt that examples in this thread are so trivial, and gave people an impression that references are not very useful. I'll throw in another example:


template<class X> void Swap(X & a, X & b)
{
X c; // I didn't use "X c = a;", so it won't require copy constructors.
c = a; // assignment operators should be defined using references
a = b; // to be efficient as in my previous post.
b = c;
}

The above template function should work for any class, as well as for built-in types, as long as the assignment operator is properly defined for the class. Without references, writing such template won't be this easy and efficient.

The primary difference between pointers and references may be just syntax. But sometimes, syntax is very important. Initially, I didn't get the importance of references either. But, for example, when you write a template function or class, it's very important that class objects and built-in type objects behave in the same way.

Gil

MarkCollette
Jun 19, 2006, 05:15 PM
Sorry to hear your code didn't even crash. If it did, it would've been much easier to find the bug :). I'm a bit surprised none of your compilers didn't give you an error. If I'm not mistaken, references were alreay in in the 1st edition of Stroustrup's book back in the late 80s.

I didn't write the code, just fixed it.

The primary difference between pointers and references may be just syntax. But sometimes, syntax is very important. Initially, I didn't get the importance of references either. But, for example, when you write a template function or class, it's very important that class objects and built-in type objects behave in the same way.

Right, when you start putting non-trivial objects into STL (we used RogueWave) containers, then you pretty much have to override half a dozen of the default operator methods. Unfotunately, it's a bit adhoc, because there's no explicit interface to implement. It's just that, depending on your class, some of the default operator implementations will work fine, and some won't.

In the case of that code, it was C++ code to work with ObjectStore, which is an object oriented database. Sortof like how the VM writes memory pages to disk, but with transactional support. So you're dealing with straight memory objects, and also database objects cached in RAM. So, very important to override everything properly with deep copies of data, etc.