3

What is the difference between these two ways of writing a function in C++? Are they both "pass by reference"? By "pass by reference", I mean that the function has the ability to alter the original object (unless there is another definition, but that is my intention).

From my understanding, when you call f1, you pass in a "synonym" of the original object. When you call f2, you are passing in a pointer to the object. With the f2 call, does a new Object* get created whereas in with f1 call, nothing does?

f1 (Object& obj) {}
f2 (Object* obj) {}

Thanks!

irwinb
  • 993
  • 2
  • 10
  • 20
  • 2
    **NO**. They are not both "pass by reference" (hint: what is different about the semantics of assigning to `obj` inside the function?). [Evaluation Strategy](http://en.wikipedia.org/wiki/Evaluation_strategy) is a must-read and should clarify the big difference. (The latter is "pass by value [of the pointer]", but see "pass by object sharing" in the link.) –  Jun 02 '11 at 22:12
  • @pst: What I find interesting about the Evaluation Strategy link is that it has an example of passing a pointer as pass-by-reference in C. Is it any different for C++ (except that you also have the option of actual "references" in C++)? – Fred Larson Jun 02 '11 at 22:40
  • @Fred Larson Yes. I didn't notice that before. Going with the label: "Example that *simulates* call-by-reference in C"; then it can be argued it's simply showing how to *emulate* call-by-reference through the use of pointers to modify the object referenced (doh, what an overloaded term!) by the variable in the caller (or, since the changes to the object are just shared, this is arguably also "pass by object sharing" ;-) In the example -- even though the addresses are taken at different times -- the end semantics are the same, but it's more apparent that `b` is being modified. –  Jun 02 '11 at 22:48
  • (As for my use of *object* in C: as far as I understand -- and use the term -- an *object* is data accessible through an *object type*. I do not know if this use of *object* terminology carries over to C++ at all.) –  Jun 02 '11 at 22:56

5 Answers5

3

Your understanding is correct.

Technically, f2 is pass by value, with the value being a pointer, but you can use that copy of the pointer to modify the pointed-to object.

Peter Alexander
  • 53,344
  • 14
  • 119
  • 168
3

They are both pass-by-reference in a general sense, but that phrase will not normally be used to describe the pointer version because of possible confusion with C++ reference types.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • I reject this statement. It implies that they both have "pass by reference" semantics. They do not. Keeping on propagating the use of "pass by reference" to mean "pass by value [of pointer/reference]" or "pass by object sharing" is confusing. –  Jun 02 '11 at 22:14
  • 3
    @pst: They do both have "pass-by-reference" *behavior*, with different *syntax* and *semantics*. A C++ *pointer* is a *reference* in the CS language-independent sense of the word. A *reference* is passed, hence it is *pass-by-reference*. The parameter is, however, not a *C++ reference type*. – Ben Voigt Jun 02 '11 at 22:16
  • 2
    @Ben Voigt Please see [Evaluation strategy](http://en.wikipedia.org/wiki/Evaluation_strategy) for the premise of my argument. The semantics are different -- hence the terms should be different. The fact that "the object is not copied on the stack" is not relevant to "pass by reference" behavior. It is simply a property of the two independent calling strategies that happens to be the same. –  Jun 02 '11 at 22:20
  • @Ben Voigt: The pointer can be used as a reference to something else, but the fact remains that the pointer is passed by value and not by reference. – Peter Alexander Jun 02 '11 at 22:34
  • @pst: I didn't say anything about the stack. – Ben Voigt Jun 02 '11 at 23:08
  • @Ben Voigt Then I am apparently missing the difference between *behavior* and *semantics*. –  Jun 02 '11 at 23:13
  • @pst: Behavior: both versions pass a handle (which ultimately means a memory address) to the object, the function can change the original object. Semantics: The first version has an argument of reference type, object members are accessed using the `.` operator. The address can be accessed with the `&` operator. The second version has an argument of pointer type, object members are accessed using the `->` operator, and address arithmetic need only name the parameter. – Ben Voigt Jun 02 '11 at 23:24
  • @pst: It's analogous to the difference between a smart pointer and a raw pointer. Both enable the same applications (behavior). But they have different semantics. – Ben Voigt Jun 02 '11 at 23:25
  • 1
    @Ben Voigt After re-reading the posters *definition* of "pass by reference" I must agree *in the context of this post*. However, I am still opposed this term to describe the behavior -- it is somewhat akin to arguing that recursion (where TCO can be and is utilized) and loops are the same because they can both achieve the same desired result. (But yet I know people who can argue this well formally .... so it might not be such a good example ;-) –  Jun 02 '11 at 23:36
  • @pst: How about `while` and `do`-`while`? Fundamentally, they're the same behavior: a block of code which repeats as long as a condition is satisfied. But they have different semantics (the `do` variant will always run at least once). For your example, both recursive function calls and the various loop constructs are *iteration* (in the general sense). So are backward gotos, `longjmp`, and even exceptions can produce iteration. Different semantics, definitely! But if someone asks "are these two both forms of iteration", then yes, in the general sense, they are iteration. – Ben Voigt Jun 02 '11 at 23:49
  • @Ben: I see the pointer version as pass-by-value, for the following reason: if you do `obj = ...` with the pointer version, you only modify something local to the function (a copy of the pointer), and not something in the calling function (the original pointer). With the reference version, doing `obj = ...` results in modiying something in the calling function (the object). That with the pointer you can do `*obj = ...` which results in modifying the object in the calling function, is I think beside the point. – HighCommander4 Jun 02 '11 at 23:54
  • @High: `*obj = ...` is not beside the point. The point is (direct quote from question) "the function has the ability to alter the original object". – Ben Voigt Jun 02 '11 at 23:58
  • @Ben: Suppose the pointer were replaced with a handle object with a dereference() method, which returns a reference to the object, so that instead of having to do `*obj = ...`, you have to do `obj.dereference() = ...`. Sure, the handle facilitates modifying the object in the calling function, but the handle is unambiguously passed by value. I argue that a pointer is nothing more than such a handle, with a bit of syntactic sugar that allows you to use `*` instead of having to call a method (whereas a reference is something fundamentally different). – HighCommander4 Jun 03 '11 at 00:04
  • @High: Couldn't you say a reference is also exactly such a handle, except that it overloads `operator=` to overwrite the referent? Also, it's a pointer that is the fundamental type, and a reference is a pointer with a bunch of syntactic sugar piled on (a little bit so you can say `obj` instead of `*obj`, and a lot for temporary lifetime extension with const references). – Ben Voigt Jun 03 '11 at 00:06
  • @Ben: I think overloading operator= in that way is a fundamental change. Without it, you can treat the handle and the handlee (that which is handled) as distinct objects and modify them independently. With it, the handle just becomes a synonym for the handlee. – HighCommander4 Jun 03 '11 at 00:24
  • @Ben: Here's another way to look at it: you can pass a pointer by reference, but you can't pass a reference by reference. That suggests that there is a fundamental difference between them. – HighCommander4 Jun 03 '11 at 00:25
  • @High: You also have to overload unary `operator&`, and `.` would have to be overloaded as well, but can't. Nevertheless, both pointer and reference are essentially handles at heart. Handles with different syntax, but still handles. – Ben Voigt Jun 03 '11 at 00:31
  • Java 'reference' types are like C++ pointer types. They can both be reasonably set to NULL. And also it is possible to change which object they point to during their lifetime. This is different from C++ 'reference' types. So it is OK to use 'reference' to describe pointers. – Aaron McDaid Jun 03 '11 at 00:38
  • @Aaron: Java references are *pass-by-reference* in the broad sense, but not in the narrow meaning which @pst is using (Compare: C# which has both reference handles and reference parameters, two different things). That's why in my answer I specifically said "in a general sense". – Ben Voigt Jun 03 '11 at 00:50
  • Hi @Ben, thanks for that - I'll look up those C# types now. Anyway, there is no doubt that the type `Object&` and `Object*` are different. I don't think anybody is suggesting otherwise. Even the original questioner might already have known. But they do have _some_ things in common, particularly that they can modify the `Object` such that the caller sees the changes. Does there exist a form of words that clarifies this for everyone? Perhaps you can help. – Aaron McDaid Jun 03 '11 at 01:16
2

What is the difference between these two ways of writing a function in C++? f1 is passing an object by reference, f2 is passing a pointer by value. Both have the ability to modify the object f1 directly through the reference and f2 by dereferencing the pointer.

With the f2 call, does a new Object* get created whereas in with f1 call, nothing does? f2 could allocate a new object at that address or use an already allocated object at that address depending. However passing a pointer by value will not call new it will simply be a copy of the pointer which may or may not point to a valid allocated object.

Check out the wiki link posted as a comment by pst.

AJG85
  • 15,849
  • 13
  • 42
  • 50
1

A pointer can be null where a reference can not.

See:

What are the differences between a pointer variable and a reference variable in C++?

Community
  • 1
  • 1
T.T.T.
  • 33,367
  • 47
  • 130
  • 168
  • Actually, either one CAN be null, but a reference obviously shouldn't. (Most pointers also shouldn't, but it isn't always obvious) Making a null reference and dereferencing a null pointer both produce undefined behavior. – Ben Voigt Jun 02 '11 at 23:52
1
f1 (Object& obj) {}

When you call f1, for example f1(o1):

  • obj becomes the other name for o1 (alias), that's it. So o1 is just alias for obj; they have the same address (you can check that &obj==&o1 is true)

f2 (Object* obj) {}

When you call f2,for example f1(&o1):

  • obj is created and initialized with &o1; that is similar like:
 f2(){
    Object* obj=&o1; // just for understanding what happens when you call f2(&o1)
    ...
dragon135
  • 1,366
  • 8
  • 19