Call by Reference in C++: I'm Confused!

  • Thread starter Edgardo
  • Start date
  • Tags
    Reference
In summary: C++ references are similar to Fortran arguments in the sense that they are aliases for variables passed to a subroutine or function, and that they can't be NULL. However they are much more general in their usage.
  • #1
Edgardo
706
17
I am confused by two versions of call by reference in C++. As an example two methods that square an integer (CBR stands for Call By Reference):

Code:
//Version 1
void squareCBR(int& x)
{
     x = x * x;
}

//Version 2
void squareCBR2(int* x)
{
     (*x) = (*x) * (*x);
}

Let's call the functions:

Code:
int x = 3;
squareCBR(x);
squareCBR2(&x);

1) What I don't understand is that I'm calling squareCBR(int& a)
by writing squareCBR(a). Why just a? I thought I'd have to pass an address to the function since the argument is (int& a).

2) The same question about squareCBR2(int* x). I call this function by writing squareCBR2(&x). Why &x? I thought I'd have to pass a pointer since the argument is (int* x).
 
Last edited:
Technology news on Phys.org
  • #2
&a is the address-of operator, and it returns a pointer to a.

If "a" has type "int" then "&a" has type "int*", like this

Code:
int a; //new variable a
int *x = &a; //x is a pointer to a

*x is the dereference operator, and returns the value pointed to by the pointer x. If "x" has type "int*" then "*x" has type "int", like this

Code:
int b = *x; //b is a new variable assigned value pointed to by x (ie, a)

When you pass an argument as a copy, it looks like this:

Code:
int funcByCopy(MyClass x)
{
   //stuff
}

and it is called like this:

Code:
MyClass x;
funcByCopy(x);

This is inefficient because the MyClass object must be copied onto the stack. It would be more efficient to only pass the address of the object (pass by pointer), like this:

Code:
int funcByPointer(MyClass *x)
{
   //stuff
}

MyClass x;
funcByPointer(&x);

However some people find it confusing to have to deal with memory addresses directly, because an address might point to nothing at all..which would cause compilation errors. References are a way of telling the computer to use pointers without making the programmer have to think so much about safety. Using references, it can be done like this:

Code:
int funcByReference(MyClass &x)
{
  //stuff

MyClass x;
funcByReference(x);

Notice that using references, the code can be written almost exacty the same way as with pass by copy, except that the compiler uses pointers under the hood for increased efficiency.
 
Last edited:
  • #3
In C++, a reference parameter in a function, as in "void squareCBR(int& x), has the semantics of an alias (alternate name) for the argument in the function call, e.g. "squareCBR(a)". As junglebeast notes, the compiler usually implements a reference by using a "hidden" pointer.

A significant practical difference between a reference and a pointer is that whereas you can change what a pointer points to, e.g.

Code:
int a = 5;
int b = 10;
int *p = &a;
cout << "p points to " << *p << endl;  // should display "p points to 5"
p = &b;
cout << "p points to " << *p << endl;  // should display "p points to 10"

you cannot change what a reference points to, in a similar fashion.
 
  • #4
Dear junglebeast and jtbell,

thanks for your help! It has become very clear to me now.
I'd still like to mention why I didn't understand call by reference:

1) I didn't know what a reference is, e.g.
Code:
int x = 12;
int& otherNameForX = x;
otherNameForX = 24;     // The value of x is also changed to 24
As jtbell mentions, otherNameForX is just an alias for x.

2) The different uses of & :
Code:
int x = 12;
int* pointerToX = &x    // <--- &x is an address;
int& otherNameForX =x;  // <---- int& stands for a reference
I've thought about & only in the context of addresses.

3) I realized what a function actually does. For example:
Code:
void funcPointer(int* p){
      *p = *p + 2;
} 

int main(){

    int x = 12;
    funcPointer(&x);

return 0;
}

is equivalent to

Code:
int main(){

    int x=12;
    
    int* p = &x;
    *p = *p + 2;

return 0;
}

In short: What I realized, thanks also to junglebeast, is the following:
When passing an address &x to funcPointer(int* p) the following assignment happens:
funcPointer(int* p = &x).

The same goes for funcRef(int& alias). When passing x to the function the following assignment happens: funcRef(int& alias = x).

Realizing that this assignment occurs I can now understand what kind of "thing" I have to pass to the functions (either &x or x).

Correct me if this is wrong.
 
Last edited:
  • #5
Yes references are just a way of hiding the pointer.
Also references are disliked by a lot of programmers because they don't look like pointers.

So "function(int*x)" is clear that it is passing an int that is likely to be changed, while "function(int& x)" looks like it is just passing an int but could be changing it.
Some common (although not universal) advice is to only pass const references.

So "function(foo *_foo)" would be called with function(&_foo) making it clear that you are changing _foo while "function(foo& _foo)" called with function(_foo) doesn't change anything.
 
  • #6
In my experience, programmers who first learned pointers (in C or some other language) tend to dislike references, whereas programmers who first learned references (e.g. in Fortran or Pascal) tend to dislike pointers. :smile:

I first learned to program in Fortran many years ago, when arguments to Fortran subprograms and functions were always passed by reference, and pointers did not exist in the language. Therefore C++ references feel "natural" to me.
 
  • #7
jtbell said:
When arguments to Fortran subprograms and functions were always passed by reference.
Stuff like this was always fun to do in early versions of Fortran:

Code:
      call settotwo(1.0)
      a = 1.0
c     a ends up == 2.0
      end

      subroutine settotwo(x)
      x = 2.0
      return
      end

some compilers treated (0) as a pointer, initializing x(0) to point to &x(1)

Code:
      integer pointer(1)
      integer array(10)

c     set pointer to array
c     after this, pointer(1) == array(1), access to pointer(1) is forever lost
      pointer[0] = array[0]

c     set pointer to absolute value (was used to access os system globals)
      pointer[0] = 32
 
Last edited:
  • #8
Thank mgb_phys. You explained very well the "danger" of using references.
 
  • #9
By the way, the "references versus pointers" argument is an old and common one among C++ programmers. Try a Google search on something like "references versus pointers in C++" and you'll get many points of view. :smile:
 
  • #10
mgb_phys said:
Yes references are just a way of hiding the pointer.
Not quite. For one thing, you can't change a reference. A reference someType & foo is similar to someType * const foo. Note that I said similar to, not equivalent to. There is no such thing as a null reference.

Some common (although not universal) advice is to only pass const references.
e.g., google: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showone=Reference_Arguments#Reference_Arguments

I disagree with this rule. As mentioned above, there is no such thing as a null reference. This alone is, IMHO, a reason to prefer references over pointers. A defensive programmer will check that a pointer passed as an argument is not null prior to referencing the pointer. This opens several cans of worms. What to do if it is null? Do you throw an exception, abort, return an error code? Whatever the case, the use of a pointer as opposed to a reference has made the job of documentation a bit harder, possibly considerably so, and has added the need for a new test case to achieve 100% code coverage.

My projects do offer an out to the above: In the function's documented assumptions and limitations, specify that pointers are assumed to be valid (non-null). This is not a preferred usage of the assumptions and limitations; it usually becomes software ticket. Assumptions are intended to address physical assumptions like bodies are rigid, slow mass depletion doesn't affect dynamics, etc.

Our rule is to disallow pass by reference for primitive types but to prefer pass by reference for structured types.
 
Last edited by a moderator:
  • #11
D H said:
I disagree with this rule. As mentioned above, there is no such thing as a null reference. This alone is, IMHO, a reason to prefer references over pointers. A defensive programmer will check that a pointer passed as an argument is not null prior to referencing the pointer.
That can also be a problem.
If you want the pointer to be null to say that the function allocates the memory or you want a default value for an unused parameter you need to have some field inside the referenced object marking if it is valid or not which breaks RAII
 
  • #12
I agree. References cannot be used if the thing being pointed to legitimately can be nothing, is not known at the time the variable is instantiated, if the pointer itself can change, and I am sure there are other places where references just won't work. You have to use pointers in such cases, and that means you have to be a bit more careful.
 

What is "Call by Reference" in C++?

"Call by Reference" in C++ is a way of passing arguments to a function by directly referencing the original variables. This means that any changes made to the variables within the function will also affect the original variables outside of the function.

How is "Call by Reference" different from "Call by Value" in C++?

In "Call by Value", a copy of the argument is passed to the function, so any changes made to the argument within the function will not affect the original variable. In "Call by Reference", the original variable is passed and any changes made to it will be reflected outside of the function.

Why would I use "Call by Reference" in C++?

"Call by Reference" is useful when you want to modify the original value of a variable within a function. This can be more efficient than creating a copy of the variable, as in "Call by Value". It is also necessary when you want to return multiple values from a function.

Can I use "Call by Reference" with any data type in C++?

Yes, "Call by Reference" can be used with any data type in C++. However, it is most commonly used with large or complex data types, such as arrays or objects, to avoid creating unnecessary copies of these data types.

Is "Call by Reference" the same as passing a pointer in C++?

No, "Call by Reference" and passing a pointer in C++ are not the same. When using "Call by Reference", the original variable is passed to the function, while passing a pointer means passing a memory address. This means that "Call by Reference" can only modify the original variable, while passing a pointer can also modify the value at the memory address.

Similar threads

  • Programming and Computer Science
Replies
19
Views
2K
  • Programming and Computer Science
Replies
3
Views
721
  • Programming and Computer Science
Replies
2
Views
680
  • Programming and Computer Science
Replies
4
Views
3K
  • Programming and Computer Science
Replies
34
Views
2K
Replies
63
Views
3K
  • Programming and Computer Science
Replies
12
Views
1K
  • Programming and Computer Science
2
Replies
36
Views
2K
  • Programming and Computer Science
Replies
3
Views
1K
  • Programming and Computer Science
Replies
20
Views
1K
Back
Top