[FAQ] What is call-by-value and call-by-reference? (AKA pass-by-value and pass-by-reference)

Pages: 123
But "call-by-" implies a calling convention, like "call-by-stdcall" or "call-by-fastcall", etc...
I guess it just doesn't make sense to me. Oh well.
Technically "call-by" is not talking about argument passing, but it is commonly used as such.

The issue at heart is, I think, what am I passing to the function? And as consequent, how does it get there?

Keeping it simple, we'll talk about ints.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void by_value( int n )
  {
  n = 7;
  }

void by_pointer( int* n )  // aka, pass by indirect reference
  {
  *n = 8;
  }

void by_reference( int& n )  // aka, pass by direct reference, or pass by alias
  {
  n = 9;
  }

#include <iostream>
using std::cout;
int main()
  {
  int n = 2;
  by_value( n );      cout << n << endl;
  by_pointer( &n );   cout << n << endl;
  by_reference( n );  cout << n << endl;
  }
2
8
9

We all understand pass-by-value: a copy of n's value is passed as argument to the function -- hence the function as a local copy of n to play with.

We all understand pass-by-(direct)-reference / pass-by-alias: an alias for n is passed as argument to the function -- hence the function's n is (for all intents and purposes) the same thing as main()'s n.

But somehow when we start talking about pass-by-(indirect)-reference, we all seem to start paying too much attention to the trees. But we are still passing that n into the function, only we have done it by passing its address, such that the function's formal parameter is a pointer, which we must explicitly dereference to get at main()'s n.

Here is where we must pay attention to the formal arguments, and it is where Grey Wolf's information has merit. The address of n is passed by value. We must dereference that value (the address) to get at the object we want to view/manipulate.
Duoas wrote:
The address of n is passed by value. We must dereference that value (the address) to get at the object we want to view/manipulate.

In C++, the value of the pointer (function argument) is copied to create a new pointer (function parameter). We must dereference that pointer to get a *reference*. That *reference* may be then used to view/manipulate the object.

You could also pass an iterator, or a ref wrapper, or any other object that holds a reference. It's still pass by value, although it does, indeed, indirectly transfers a reference.
Last edited on
closed account (3hM2Nwbp)
Shouldn't the owner of the Java language specify a concrete answer to this? (Ref: Java Debate)

Both sides of the argument are equally as valid in my eyes.
Last edited on
Cubbi wrote:
In C++, the value of the pointer (function argument) is copied to create a new pointer (function parameter). We must dereference that pointer to get a *reference*. That *reference* may be then used to view/manipulate the object.
Yes, well-put.

Cubbi wrote:
You could also pass an iterator, or a ref wrapper, or any other object that holds a reference. It's still pass by value, although it does, indeed, indirectly transfers a reference.
C++ "references" are always aliases, even if you keep them in some other container that you pass to the function -- but then, we'd be passing something different to the function, no?

Luc Lieber wrote:
Shouldn't the owner of the Java language specify a concrete answer to this? (Ref: Java Debate)
I don't see Mr. Gosling caring that much. (I think he's a wacko, and his ideas, as implemented in Java, are nuts. But that's me.)

His JVM was pretty bright, though. (See, it pays to play around with Pascal!)
In C++, the value of the pointer (function argument) is copied to create a new pointer (function parameter). We must dereference that pointer to get a *reference*. That *reference* may be then used to view/manipulate the object.

You could also pass an iterator, or a ref wrapper, or any other object that holds a reference. It's still pass by value, although it does, indeed, indirectly transfers a reference.


+1. Yes, it is still pass by value.


There is an important conceptual difference between passing an object by reference and passing something (like a pointer or an iterator) that can be used to reach an object. A function to which an object is passed by reference always operates on an object. A function to which a pointer to an object is passed may not get an object to operate on.

Pass an object by reference: conceptually, an object is always passed.

Pass a pointer to an object: conceptually, an object may be (indirectly) passed.

Though it is irrelevant to this particular discussion, the C++ equivalent of a Java reference is a pointer (and not a reference). The null reference in Java is the C++ nullptr.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// An object is always passed to this function
void pass_by_reference( std::string& str )
{
    // reference_to_int is conceptually an alias for an object of type int
    // the integer referred to must exist, the reference is always valid

    str += "!!!" ;  // this is always safe, the behaviour is well-defined
}

// An object is sometimes (indirectly) passed to this function
// Sometimes it is called with no object at all
void pass_pointer_by_value( std::string* pstr )
{
    // pointer_to_int may contain the address of an integer
    // or may not point to any integer at all

    *pstr += "!!!" ; // this may lead to undefined behaviour.
    // it will, if pointer_to_int == nullptr
}

// every object of type A is initialized using a string
struct A { A( const std::string& str ) ; A( const A& ) = delete ; char cstr[1024] ; }; 

// some objects of type B may be initialized using a string
struct B { B( const std::string* pstr ) ; B( const B& ) = delete ; char cstr[1024] ; }; 




Last edited on

Yes, it is still pass by value


So then, java is also pass-by-value. In java you pass always references (pointers), not objects themselves. To access the object, you need to dereference it, and "." and "[]" are Java's dereference operators. Try calling "." on a null reference. You get NPE = Null Pointer Exception. It is called pointer! See it? Even "==" and "!=" compare references, not objects. You may argue it is not useful, but it is definitely consistent, and it is also the default way taken in other languages (e.g. Ruby, Python, PHP, Scala, C#, JavaScript).


Last edited on
closed account (z05DSL3A)
rapidcoder wrote:
So then, java is also pass-by-value.
Java is probably better described as call-by-sharing[1] however this term is not used much and the Java community seem to say it is call-by-value.


[1] http://www.pmg.lcs.mit.edu/papers/thetaref/node34.html
I don't see Mr. Gosling caring that much.


There is exactly one parameter passing mode in Java -- pass by value -- and that helps keep things simple. -- James Gosling, "The Java Programming Language, Second Edition"

(I don't have the book, I'm just quoting someone else's answer from stackoverflow)
If you argue like that then this thing called "pass by reference" belongs in the realm of fairytales like unicorns and dragons, because you will never get to the point where you can pass a reference without having to pass the value of that reference.
My point exactly.

void myFunc(myClass& M) { .. }
Am I passing an object by reference, or a reference by value? I can't bind M to something else [with effect outside the function].
closed account (z05DSL3A)
hanst99,

When you create a reference, the referent is NOT evaluated (it is not turned into the value that it represents). The address of the object is take, this is not the value of the object. That is why it is not pass-by-value.

Edit:
P.S. Dragons do exist.
Last edited on
Pointers are passed by value, but pointers are references so if you say "pass an integer by reference" you probably mean "pass a pointer to integer" is what I'm saying.
The nice feature about references is they give the compiler a great deal of latitude when optimizing. We say it is an alias from our (the programmer's) point of view.

Underneath, it may actually be a pointer. But if the right optimizations can be done, it may actually be the referent.

They steal your socks, but only the left ones. What's with that?
I never said that references are pointers, I said that pointers are references.

(actually, I just saw that my last post could be read that way, sorry about that).
closed account (z05DSL3A)
Now you are getting into another pet peeve, with the references. A pointer references an object, a reference references an object, a pointer is a reference but it is not a reference.

So back to the point(er) in hand. Pointers hold a value (the address of the object it points to), this value is passed to the parameter when it is created.
Just wondering:

1
2
myClass m;
myClass& rm = m;

What does 'rm' hold exactly? Is it an address that is dereferenced on use? My compiler says a reference member of a class adds 4 bytes to its size, but what other 4byte information can it use to identify an object?
closed account (zwA4jE8b)
m and rm are both variable names that access the same memory location. if you do anything to m or rm the same instance of myClass will be changed.
Last edited on
> Even "==" and "!=" compare references, not objects. You may argue it is not useful

It is not just useful, the notion of the identity of an object is fundamental to object-oriented programming. The notion of logical equivalence of objects is another useful, fundamental concept.

In C++, we do not even think of this as an issue: objects have a binding to an address in memory, and that binding gives us the identity of the object:

1
2
3
4
5
6
7
8
template< typename T > void foo( T& a, T& b )
{
    // test for object identities - is it the same object? : 
    bool are_a_and_b_the_same_object = std::addressof(a) == std::addressof(b) ;

    // test for logical equivalence of the objects - are the two logically equivalent?
   bool are_a_and_b_logically_equivalent = a == b ;
}


Pointer-disadvantaged languages have to choose == to stand for either one or the other. Java chose == to stand for a test of object identity. Because a test for logical equivalence of objects is also fundamental, it provided for that via a virtual function in the base class Object:
/* virtual */ bool Object::equals( Object* that ) ; // paraphrased into C++
In that case, probably #define rm m

¿Because you left them?
Pages: 123