2

It is said that in Java method arguments are passed by value which is true for primitives and for objects, object's reference is passed by value. To illustrate consider the code:

class Test {
 private static void dateReplace (Date arg) {
        arg = new Date (arg.getYear(), arg.getMonth(), arg.getDate() +1);
        System.out.println ("arg in dateReplace: " + arg);
    }

 public static void main(String[] args) {

      Date d1 = new Date ("1 Apr 2010");
        dateReplace(d1);
        System.out.println ("d1 after calling dateReplace: " + d1);
    }
}

this will print:
arg in dateReplace: Fri Apr 02 00:00:00 2010
d1 after calling dateReplace: Thu Apr 01 00:00:00 2010.

What is the C++ equivalent that would give same results?

What is C++ equivalent that would give the value of d1 after calling the method to be the same value as within the method i.e. the caller see the modified value?

ace
  • 11,526
  • 39
  • 113
  • 193
  • Is this homework? You probably want to read up on C's * (indirection) and & (reference) operators. – eggyal May 07 '11 at 15:44
  • 3
    @eggyal Neither C nor C++ have a reference operator - & is the address-of operator. –  May 07 '11 at 15:51
  • @unapersson: what's the difference? :s – eggyal May 07 '11 at 16:00
  • @eggyval In C++, you deal differently with pointers and references. `&foo` gets you the pointer to `foo`, and dealing with it will require you to use the pointer syntax (you'll have to access members with the `->` operator for instance). When you pass an object by reference, it's exactly as if it was a value (you use the `.` operator to access members). – zneak May 07 '11 at 16:05
  • I stand corrected. Thank you. – eggyal May 07 '11 at 16:19
  • 1
    @Alan, it happened many a year ago when I was trying to figure out the object-oriented programming and I finally managed to when I saw how it looked in assembler. To achieve what Java does in C++, you simply need to pass primitives by value and objects by pointer. Since there is no explicit GC you may need to free/delete objects if you happen to create some. – bestsss May 07 '11 at 16:34
  • This may be worth reading: http://stackoverflow.com/questions/5174725/how-do-you-explain-c-pointers-to-a-c-java-developer/5174827#5174827 – Martin York May 07 '11 at 17:58
  • As far as I know Java method arguments are parsed by value, but an actual copy of the value is made before the method enters the first line. – Koekiebox May 08 '11 at 10:39

3 Answers3

6

C++ does not have the same semantics as Java for values and references. At first, every type has the potential to be either passed by copy or by reference or by address (you can however prevent types to be passed by copy by hiding the copy constructor).

The passing type the most closely related to Java's "by reference" passing is by pointer. Here are an example of the three:

void foo(std::string bar); // by copy
void foo(std::string& bar); // by reference
void foo(std::string* bar); // by address

As a side note, passing by copy is always more expensive than passing by reference or pointer for types that are larger than the size of a pointer. For this reason, you may also often prefer to pass by const reference, which will allow you to read an object without having to copy it.

void foo(const std::string& bar); // by const reference

However, this is all tricky and you need to be aware of Java subtleties to decide correctly what you want in C++. In Java, you're not actually passing objects by references: you are passing object references by copy. That is, if you assign a new object to an argument, the object of the parent scope won't change. In C++, this more closely matches passing objects by address than by reference. Here's an example of how this is important:

// Java using "object references":
public static void foo(String bar)
{
    bar = "hello world";
}

public static void main(String[] argv)
{
    String bar = "goodbye world";
    foo(bar);
    System.out.println(bar); // prints "goodbye world"
}

// C++ using "references":
void foo(std::string& bar)
{
    bar = "hello world";
}

int main()
{
    std::string bar = "goodbye world";
    foo(bar);
    std::cout << bar << std::endl; // prints "hello world"
}

// C++ using pointers:
void foo(std::string* bar)
{
    bar = new std::string("goodbye world");
    delete bar; // you don't want to leak
}

int main()
{
    std::string bar = "goodbye world";
    foo(&bar);
    std::cout << bar << std::endl; // prints "hello world"
}

In other words, when you use references in C++, you're really dealing with the same variable you passed. Any change you do to it, even assignations, are reflected to the parent scope. (This is in part due to how C++ deals with the assignation operator.) Using pointers, you get a behavior more closely related to the one you have with Java references at the cost of possibly having to get object addresses through the unary & operator (see foo(&bar) in my example), needing to use the -> operator to access members, and some additional complexity for using operator overloads.

Another notable difference is that since the usage of by-reference arguments is syntactically closely related to the usage of by-copy arguments, functions should be able to assume that the objects you pass by reference are valid. Even though it's usually possible to pass a reference to NULL, this is very highly discouraged as the only way to do it is to dereference NULL, which has an undefined behavior. Therefore, if you need to be able to pass NULL as a parameter, you'll prefer to pass arguments by address rather than by reference.

Most of the time, you'll want to pass by reference instead of by address when you want to modify an argument from a function because it is more "C++ friendly" (unless you need the NULL value), even though it's not exactly like what Java does.

zneak
  • 134,922
  • 42
  • 253
  • 328
  • 1
    Java may call them object references. But they are more like C++ pointers than references as they can be NULL. So I just think of Java objects as garbage collected pointers which is basically the equivalent to a C++ shared pointer (which is just a much finer grain garbage collected pointer). – Martin York May 07 '11 at 18:00
1

C++ passes by value by default. You can implicitly pass by reference by writing the function to accept a reference, or explicitly by passing a pointer.

Consider the following three examples:

FooByValue(Foo arg)
{
  //arg is passed by value.
}

FooByReference(Foo & arg)
{
  //arg is passed by reference.
  //changes made to arg will be seen by the caller.
}

FooByPointer(Foo * arg)
{
  //arg is passed by reference with pointer semantics.
  //changes made to the derefenced pointer (*arg) will be seen by the caller.
}

You can then call the above as follows Foo anObject;

FooByValue(anObject); //anObject will not be modified.
FooByRefence(anOBject); //anOBject may be modified.
FooByPointer(&anObject); //anObject may be modified.

The & symbol when applied to a variable like &anOBject is used to get the address of the variable, basically giving a pointer to the location in memory that variable is stored in.

FooByValue() operates like your example, and FooByReference() will keep any changes made to the arguments after the function call, as the argument will not be copied, its actual location in memory will be shared.

Ephphatha
  • 586
  • 2
  • 8
  • Wrong. Nothing is passed by reference in C++. This is a common misconception. You pass a reference/pointer by value. If it was passed by reference, you could modify the parameter itself (and not just the object it points to/references). – Tamás Szelei May 07 '11 at 15:51
  • 5
    @Tamas You seem to have your own private meaning for the term "pass by reference". –  May 07 '11 at 15:55
  • If you pass an object by a pointer, can you modify the pointer inside the function so it points elsewhere and the change is reflected outside? You can do this in Pascal for example, because it actually has [pass-by-reference semantics](http://www.hkbu.edu.hk/~bba_ism/ISM2110/pas045.htm). You can't do this in C++. – Tamás Szelei May 07 '11 at 15:58
  • 2
    @Tamas Yes it does, in exactly the same way C++ does. You see that `var` in front of the parameter list in the code you linked to? That is exactly the same as declaring a parameter as a reference in C++. By default var is not used, and Pascal is pass by value. And do you seriously think you cannot write a swap() function in C++???? –  May 07 '11 at 16:03
  • std::swap (and any other swap implementation you can do in C++) will not change the parameters itselves but the contents in memory where they point to. To change the value of the pointer parameter (change where it points) you'd have to add another level of indirection. Of course you can't change where a reference points after it was initialized anyway, but that's not the point. – Tamás Szelei May 07 '11 at 16:18
  • @Tamás: no, that is *exactly* the point. When you use references in C++, you do *pass by reference* in the truest sense of the word. What you're saying is true for Java references, and for pointers, but not for C++ references. – jalf May 07 '11 at 16:21
  • 1
    I was wrong. Thank you for explaining it in a respectful, calm way. – Tamás Szelei May 07 '11 at 16:25
  • When you pass a C++ reference to a function, you pass an alias of the object *itself*. That is exactly what "pass by reference" means. In Java, when you pass a reference, the callee gets its copy of the reference to the object, which can be then modified (for example to point to another object, or set to null) without the change being visible to the caller. That, as you correctly say, is passing the reference by value. But with a C++ reference, the callee sees *the object itself* (try taking the address of the reference, if you're in doubt) – jalf May 07 '11 at 16:25
  • 1
    No, I understand now. As you said the first time, I confused Java reference semantics with the one in C++. Thank you again. – Tamás Szelei May 07 '11 at 16:31
0
class Test {
 void dateReplaceReference(Date& arg) {
   // arg is passed by reference, modifying arg 
   // will modify it for the caller
 }
 void dateReplaceCopiedArgument(Date arg) {
   // arg is passed by value, modifying arg 
   // will not modify data for the caller
 }
 void dateReplaceByPointer(Date* arg) {
   // arg is passed as pointer, modifying *arg 
   // will modify it for the caller
 }
};

Note that passing as reference or by pointer is the same thing. The only difference is how you want access the data, by a "." or by "->". Also, you cant pass a null value to a method taking a reference.

rtn
  • 127,556
  • 20
  • 111
  • 121
  • actually, modifying `*arg` will modifying data in the caller. Modifying `arg` will not. – nos May 07 '11 at 16:00
  • Yeah that's wrong. Accessing something through a pointer WILL change the object for all users. The only way to make changes invisible is the 2nd method, where the copy constructor is called for arg and only the copy given to the callee. – Voo May 07 '11 at 16:37