pass by reference

Started by
35 comments, last by phresnel 14 years, 12 months ago
This question is kind of remedial and I could probably get by without knowing the answer but it's bothering me. Here's my test code:

#include <iostream>

void Intprinter(int inum);
void Intprinter2(int &inum);
void Intprinter3(int *inum);

int main()
{
  int *ival;
  int inum;

  ival=new int;
  *ival=5;
  inum=5;

  Intprinter(inum);
  Intprinter(*ival);
  Intprinter2(inum);
  //Intprinter2(&inum);
  //Intprinter2(ival);
  Intprinter2(*ival);
  Intprinter3(ival);
  Intprinter3(&inum);

  delete ival;
  return 0;
}

void Intprinter(int inum)
{
  std::cout<<inum<<"\n";
}

void Intprinter2(int &inum)
{
  std::cout<<inum<<"\n";
}

void Intprinter3(int *inum)
{
  std::cout<<*inum<<"\n"; 
}

Every line except for the two that are commented out output "5" to the screen. The ones that are commented out will not compile. It looks like Intprinter needs an integer value. So you can pass it an integer or you can dereference an int pointer and send the value. Intprinter3 expects an int pointer or the memory address of an int. So you can pass it an int pointer or you can reference a regular integer and send that. What I don't fully understand is Intprinter2 (pass by reference). It looks like all you can possibly send it is a regular integer or a dereferenced pointer, just like Intprinter(int inum). And the function itself somehow magically only takes the memory address of it. You can't send the function a referenced int or an int pointer, it expects a regular int no matter what. I guess what I don't understand is why does pass by reference even exist? Why not just make a function that expects a pointer like Intprinter3 and then just reference values before you pass them, like on my last call to Intprinter3? I mean isn't that the exact same thing? Although then you would have to dereference everything inside of the function.
Advertisement
Quote:Original post by icecubeflower
What I don't fully understand is Intprinter2 (pass by reference). It looks like all you can possibly send it is a regular integer. And the function itself somehow magically only takes the memory address of it. You can't send the function a referenced int or an int pointer, it expects a regular int no matter what.
Yes, a reference is internally handled like a pointer, but without having to dereference it.

Quote:Original post by icecubeflower
I guess what I don't understand is why does pass by reference even exist? Why not just make a function that expects a pointer like Intprinter3 and then just reference values before you pass them, like on my last call to Intprinter3? I mean isn't that the exact same thing? Although then you would have to dereference everything inside of the function.
Reasons I can think of offhand:
1. You want to change the value of the parameter passed in, but that value is not optional. If it was optional you could use a pointer, and pass null as "I don't care about this parameter"
2. You can pass a parameter as const reference, which makes the function look tidier (No need for the address-of operator everywhere), and doesn't have the same overhead as using pass-by-value (Non-POD types will need a copy made to pass to the function which could be expensive - E.g. a std::vector with a few MB of memory allocated to it).

Moving this thread to For Beginners.
You are not the only one confused as to why references even exist.

I am not a big fan myself...
While the C++ FQA has some valid points (since naturally C++ has problems), it also contains a whole lot of what seems utter rubbish, since the aim is to critisize every single aspect of C++ as well as every single question/answer on C++ FAQ (which is a very nice online learning material to widen your understanding of C++).

Quote:
Which means that you can't understand the effect of a statement as simple as a=b; without knowing whether a is a reference or not.


What does that mean? How does the fact that foo has an instance and bar has a reference change the meaning of a = b;

X b;void foo(X a){    a = b;    //...}void bar(X& a){    a = b;    //...}


In both cases the assignment does *exactly* the same thing, as the FAQ says (naturally the consequences to calling code would be different, but that would sort of be the intention of code like that).

Quote:
they make pointers to objects feel like objects, but for most purposes that can be achieved with typedef TStruct* T


I would really like an explanation how one would be able to write a generic algorithm for both vector and list (etc) without the concept of iterators that abstract away the differences in access to the underlying container...

Quote:
templates - a duplicate facility solving some of the problems of C macros and creating new, frequently more costly and complicated problems.


Duplicate?... One is simple token substitution without any idea of what the code means?

Quote:
Operator overloading is also useful for providing user-defined containers such as strings and vectors, duplicating the functionality of built-in strings and arrays.


What built-in strings (or even arrays which decay to pointers everywhere)? Am I missing something?

One could go on and on.
Quote:Original post by icecubeflower
I guess what I don't understand is why does pass by reference even exist?

To make operator overloading look nice.

a + b // nice
&a + &b // ugly
Quote:Original post by DevFred
Quote:Original post by icecubeflower
I guess what I don't understand is why does pass by reference even exist?

To make operator overloading look nice.

a + b // nice
&a + &b // ugly


Wouldn't &a + &b just be adding the pointers to the pointers to a and b? Wouldn't you need to use *a + *b in this case?

@OP Why does any "syntactic sugar" exist? You could make the very same argument for classes and structs, if-then-else and the : ? operator, or even while and for.

They are functionally the same/interchangeable, but you can establish your own conventions for using one or the other to make things more readable.
Check out the first gameplay video from my javascript/PHP RTS game
Quote:Original post by MortusMaximus
Wouldn't &a + &b just be adding the pointers to the pointers to a and b?

No, you cannot add two pointers, that doesn't make sense. If there was no pass-by-reference, you'd have to pass the adresses of your objects to user-defined operator overloads.

Quote:Original post by MortusMaximus
Wouldn't you need to use *a + *b in this case?

If a and b are objects of some user-defined type, the expressions *a and *b don't make any sense.
Quote:
If there was no pass-by-reference, you'd have to pass the adresses of your objects to user-defined operator overloads.


And hence it would become impossible to write generic code that would work with user-defined and built-in types alike.

But then, in the spirit of C++ FQA you'd be using some kind of macros anyway instead of the "evil" templates. :)
Quote:Original post by MortusMaximus
Wouldn't &a + &b just be adding the pointers to the pointers to a and b? Wouldn't you need to use *a + *b in this case?
You're correct on both points, but I think DevFred was talking about the actual implementation of operator+, rather than what you would do in a pass-by-reference rather than pass-pointer-by-value function. That is, if there were no references, it would be necessary to implement operator overloading on pointers rather than values in order to maintain performance, resulting in ugly code.
Quote:Original post by icecubeflower
And the function itself somehow magically only takes the memory address of it. You can't send the function a referenced int or an int pointer, it expects a regular int no matter what.


The function call might be implemented in basically that way in the generated code, but the semantics are that you pass a value. The difference between passing by reference and passing by value is that when you pass by reference, you pass the value, rather than a copy of it.

Quote:I guess what I don't understand is why does pass by reference even exist? Why not just make a function that expects a pointer like Intprinter3 and then just reference values before you pass them, like on my last call to Intprinter3?


1) Because taking addresses of things is extra work for the programmer.
2) Because taking addresses of things is error-prone.
3) Because for a given type T, a T* could be NULL, be invalid (uninitialized or pointing at memory that doesn't belong to the program or pointing at memory that doesn't represent a T), point to a valid single T, or point to an element of an array of T, but a T& can only refer to a valid single T. Making guarantees like this makes it easier to prove that code does the right thing.

4) Because
Quote:then you would have to dereference everything inside of the function.


This topic is closed to new replies.

Advertisement