1

In C++, are all types passed by value unless it comes with a & or * symbol?

For example in Java, passing an array as a function argument would be by default passing by reference. Does C++ give you more control over this?

EDIT: Thanks for all your responses, I think I understand the whole pass-by-value thing more clearly. For anyone who is still confused about how Java passes by value (a copy of the object reference), this answer really cleared it up for me.

Community
  • 1
  • 1
Chara
  • 1,045
  • 10
  • 21
  • 1
    Even in java, objects are passed by value. Ideally, considering objects as passing by reference makes it more understandable and that may be the reason why some books and references have called passing objects as `pass by reference`. Java follows pass by value and there is nothing like `pass by reference` in it. – Mathews Mathai Feb 19 '16 at 18:05
  • In the case of passing an array, C++ provides vector as another option. I just put this sentance in the wrong place, to all the down-voters. – WhatsUp Feb 19 '16 at 18:08
  • I would refrain from saying terms like "value" and "reference" when comparing two languages and how they handle parameters. Those terms for C++ mean specific things. Those terms for Java mean specific things. For another language, again, specific things. – PaulMcKenzie Feb 19 '16 at 18:08
  • In Java, a "reference" is a kind of value, and the word "reference" used to refer to these values has nothing to do with "pass by reference". "Pass by reference" and "pass by value" refer to whether a function is passed a reference to a variable or the value of a variable. – molbdnilo Feb 19 '16 at 18:09
  • Note that C++11 added `&&` to the mix. – Christian Hackl Feb 19 '16 at 18:26

2 Answers2

7

In C++, are all types passed by value unless it comes with a & or * symbol?

No if you pass something as * parameter (a pointer thereof) it is still passed by value. A copy of the pointer being passed is made. But both the original and copy point to the same memory. It is similar concept in C# - I believe also in Java, just you don't use * there.

That is why if you make changes to the outer objects using this pointer (e.g. using dereferencing), changes will be visible in original object too.

But if you just say assign a new value to the pointer, nothing will happen to the outer object. e.g.

void foo(int* ptr)
{
  // ...
  // Below, nothing happens to original object to which ptr was 
  // pointing, before function call, just ptr - the copy of original pointer - 
  // now points to a different object 
  ptr = &someObj; 
  // ...
}

For example in Java, passing an array as a function argument would be by default passing by reference. Does C++ give you more control over this?

In C++ or C if you pass array (e.g. int arr[]), what is being passed is treated as pointer to the first element of the array. Hence, what I said above holds true in this case too.

About & you are correct. You can even apply & to pointers (e.g., int *&), in which case now, the pointer indeed gets passed by reference - there is no copy made.

Giorgi Moniava
  • 27,046
  • 9
  • 53
  • 90
5

Probably tangential to your question, but I often take another direction to understand what happens when you call a function in C++.

The difference between

void foo(Bar bar);  // [1]
void foo(Bar& bar); // [2]
void foo(Bar* bar); // [3]

is that the body in [1] will receive a copy of the original bar (we call this by value, but I prefer to think of it as my own copy).

The body of [2] will be working with the exact same bar object; no copies. Whether we can modify that bar object depends on whether the argument was Bar& bar (as illustrated) or const Bar& bar. Notice that in a well-formed program,[2] will always receive an object (no null references; let's leave dangling references aside).

The body of [3] will receive a copy of the pointer to the original bar. Whether or not I can modify the pointer and/or the object being pointed depends on whether the argument was const Bar* bar, const Bar* const bar, Bar* const bar, or Bar* bar (yes, really). The pointer may or may not be null.

The reason why I make this mental distinction is because a copy of the object may or may not have reference semantics. For example: a copy of an instance of this class:

struct Foo {
 std::shared_ptr<FooImpl> m_pimpl; 
};

would, by default, have the same "contents" as the original one (a new shared pointer pointing to the same FooImpl pointer). This, of course, depends on how did the programmer design the class.

For that reason I prefer to think of [1] as "takes a copy of bar", and if I need to know whether such copy will be what I want and what I need I go and study the class directly to understand what does that class in particular means by copy.

Escualo
  • 40,844
  • 23
  • 87
  • 135