Does C++ pass objects by value or reference?
Asked Answered
D

6

88

A simple question for which I couldn't find the answer here.

What I understand is that while passing an argument to a function during call, e.g.

void myFunction(type myVariable)
{
}

void main()
{
    myFunction(myVariable);
}

For simple datatypes like int, float, etc. the function is called by value.

But if myVariable is an array, only the starting address is passed (even though our function is a call by value function).

If myVariable is an object, also only the address of the object is passed rather than creating a copy and passing it.

So back to the question. Does C++ pass a object by reference or value?

Delinda answered 19/1, 2014 at 10:10 Comment(9)
In the case of an array, you are passing the pointer to the first element by value. It's not passing by reference in C++ unless the argument is a reference type (it has an & in it).Euratom
@Juliannjulianna A list of books ?? :0 Seriously, downvotes?? I have to buy all those books to know answer to the question. I sorry but am saddenedDelinda
This isn't a bad question in general. But it does demonstrate that maybe you should sit down a bit with the fundamentals of the language, and experiment through a few test cases. If you did, you would quickly see that the default behavior of passing objects is to copy. You could see this by passing a std::vector<int> myVariable parameter, adding to it in myFunction and printing out there, and then printing it in main. The modifications will not be reflected in main's output. But C++ can be bent beyond these conventions; that's part of its madness and charm. Read up, don't despair!Nicole
My book didnt clarify how objects were passed, along with array passing. I was confused. I google searched and searched here. All questions were specefic. Not finding a general answer, I decided to askDelinda
duplicate? lol. somebody please fix this.Chafee
Could we please be a bit nicer to new users?. They hunt in packs around here. But don't worry about them.Urus
Good question! :) I was looking for thisListel
I think this is a perfectly valid and helpful question. I have several books on C++ and have been using it off and on for going on 5 years now (for school assignments mostly) but I can't always remember how all the different languages I am exposed to operate at their lowest level. At work I use C# and a bit of Python, C++ for random projects at home, and this last week I started getting serious about C. They all do this a bit differently and I needed a quick and easy way to refresh on this subject in C++ without digging out some 400-600+ page books.Varletry
@JosephMansfield are you sure that pass by reference means passing with & in syntax. Are not you relating pass by reference to syntatical thing instead of conceptual thing. In my view pass by reference is passing the ADDRESS whether by & or without it (as it happens in arrays).Supertax
A
80

Arguments are passed by value, unless the function signature specifies otherwise:

  • in void foo(type arg), arg is passed by value regardless of whether type is a simple type, a pointer type or a class type,
  • in void foo(type& arg), arg is passed by reference.

In case of arrays, the value that is passed is a pointer to the first element of the array. If you know the size of the array at compile time, you can pass an array by reference as well: void foo(type (&arg)[10]).

Adapter answered 19/1, 2014 at 10:14 Comment(3)
I think we should take terms carefully when talking about this. Pass by value means "What you get is the value of the parameter", and pass by reference means "What you get is a reference/alias of the parameter", independently of what the compiler really does (Copying, moving, eliding copies, passing pointers, passing references, etc). I have posted this comment because I think identifying pass by value with copy and pass by reference with no copy is a common source of missunderstandings, starting with C (Which has no pass by reference, emulates it with pointers), C++, and Java.Gerah
@Gerah C has no pass by reference. How? If pass by reference means passing the address then how C has not pass by reference? I think pass by reference is not related to REFERENCE VARIABLES but it is related to passing the address whether by pointers or reference variables.Supertax
@aLearner Pass by reference means creating an alias to already existing object. So when you use "int & a = x" you are creating new name for x. Main reason for doing so is to change the value of x when a is modified. In C there is no way to add new names to same existing objects so we take an address of a object and pass it so that we can change value of original variable. With pointer you are actually using copy by value. You are copying the value of address when you use "int * a = &x". And thats what Manu343726 mean by emulating reference by using pointers.Secunderabad
P
33

C++ always gives you the choice: All types T (except arrays, see below) can be passed by value by making the parameter type T, and passed by reference by making the parameter type T &, reference-to-T.

When the parameter type is not explicitly annotated to be a reference (type &myVariable), it is always passed by value regardless of the specific type. For user-defined types too (that's what the copy constructor is for). Also for pointers, even though copying a pointer does not copy what's pointed at.

Arrays are a bit more complicated. Arrays cannot be passed by value, parameter types like int arr[] are really just different syntax for int *arr. It's not the act of passing to a function which produces a pointer from an array, virtually every possible operation (excluding only a few ones like sizeof) does that. One can pass a reference-to-an-array, but this explicitly annotated as reference: int (&myArray)[100] (note the ampersand).

Pozzy answered 19/1, 2014 at 10:18 Comment(4)
+1 for pointing out that int arr[] is really just int *arr. That makes it clear why passing an array by value seems to work differently than other types T, because in reality is doing exactly what you would expect if you were to write int *arr instead.Varletry
@Varletry arr[] is not *arr. int arr[] declares and makes space for an array, arr is the address of the first element, not a pointer. int *arr2 declares and makes space for a pointer to an int (or the first element of an array). A pointer might receive the address of an array, arr2 = arr, but the opposite is not possible arr = .... An argument arr is a mere address, while in the case of arr2 the content of the pointer is passed.Fawcett
@Déjàvu thanks sharing. I do know that arr[] and *arr aren't the same thing, and I knew that three years ago too, so I'm not sure what I meant exactly in my previous comment. arr[] can be automatically coerced into *arr, but that doesn't make it the same thing. I wonder if I was thinking at the assembly level? The type system knows arr[] and *arr are different, but in assembly they could easily look the same when the method is called, since just a pointer to the base of the array is passed.Varletry
@Déjàvu in a function's parameter list, int arr[] and int *arr are the same type. In other contexts they are different. Blame CRoee
C
9

C++ makes both pass by value and pass by reference paradigms possible.

You can find two example usages below.

http://www.learncpp.com/cpp-tutorial/72-passing-arguments-by-value/

http://www.learncpp.com/cpp-tutorial/73-passing-arguments-by-reference/

Arrays are special constructs, when you pass an array as parameter, a pointer to the address of the first element is passed as value with the type of element in the array.

When you pass a pointer as parameter, you actually implement the pass by reference paradigm yourself, as in C. Because when you modify the data in the specified address, you exactly modify the object in the caller function.

Curie answered 19/1, 2014 at 10:22 Comment(0)
A
1

There are already very informative answers above. I am just sharing a test case in the following in hope that the future readers may find it helpful:

#include <iomanip> 
#include <iostream>
#include <vector>

struct MyStruct
{
    MyStruct(int val = 1) :dim(val) { c = new double[dim]; }
    int a = 0;
    double b[3] = { 1,2,3 };
    double* c;
    std::vector<int> vec_i;
    std::vector<double> vec_d;
    int get_dim() { return dim; }
private:
    int dim;
};

static void test_w_val(MyStruct ms, double arr[5])
{
    for (int i = 0; i < 5; i++)
        arr[i] = 2 * i + 1;

    ms.a = 10;
    ms.b[0] = 100;
    ms.b[1] = 200;
    ms.b[2] = 300;

    for (int i = 0; i < ms.get_dim(); i++)
        ms.c[i] = 1000 + i;

    ms.vec_d.push_back(1e4);
    ms.vec_d.push_back(2e4);

    ms.vec_i.push_back(50);
    ms.vec_i.push_back(60);
}

static void test_w_ref(MyStruct& ms, double (&arr)[5])
{
    for (int i = 0; i < 5; i++)
        arr[i] = 2 * i + 1;

    ms.a = 10;
    ms.b[0] = 100;
    ms.b[1] = 200;
    ms.b[2] = 300;

    for (int i = 0; i < ms.get_dim(); i++)
        ms.c[i] = 1000 + i;

    ms.vec_d.push_back(1e4);
    ms.vec_d.push_back(2e4);

    ms.vec_i.push_back(50);
    ms.vec_i.push_back(60);
}

int main()
{
    using std::cout;
    using std::endl;

    double my_arr1[5] = { 1.,2.,3.,4.,5. }, my_arr2[5] = { 1.,2.,3.,4.,5. };
    MyStruct s1(2), s2(2);

#pragma region Prior to calls
    cout << "Before calling functions\n";
    cout << "Array:\n";
    for (int i = 0; i < 5; i++)
        cout << my_arr1[i] << " ";
    cout << endl;

    cout << "Struct:\n";
    cout << "dim: " << s1.get_dim() << endl;

    cout << "a: " << s1.a << "\n";

    cout << "b: ";
    for (int i = 0; i < 3; i++)
        cout << s1.b[i] << " ";
    cout << endl;

    cout << "c: ";
    for (int i = 0; i < s1.get_dim(); i++)
        cout << s1.c[i] << " ";
    cout << endl;

    cout << "vec_i: ";
    for (int i = 0; i < s1.vec_i.size(); i++)
        cout << s1.vec_i[i] << " ";
    cout << endl;

    cout << "vec_d: ";
    for (int i = 0; i < s1.vec_d.size(); i++)
        cout << s1.vec_d[i] << " ";
    cout << endl;
#pragma endregion

#pragma region val.
    test_w_val(s1, my_arr1);
    cout << "\nTest with Val.\n";
    cout << "Array:\n";
    for (int i = 0; i < 5; i++)
        cout << my_arr1[i] << " ";
    cout << endl;

    cout << "Struct:\n";
    cout << "dim: " << s1.get_dim() << endl;

    cout << "a: " << s1.a << "\n";

    cout << "b: ";
    for (int i = 0; i < 3; i++)
        cout << s1.b[i] << " ";
    cout << endl;

    cout << "c: ";
    for (int i = 0; i < s1.get_dim(); i++)
        cout << s1.c[i] << " ";
    cout << endl;

    cout << "vec_i: ";
    for (int i = 0; i < s1.vec_i.size(); i++)
        cout << s1.vec_i[i] << " ";
    cout << endl;

    cout << "vec_d: ";
    for (int i = 0; i < s1.vec_d.size(); i++)
        cout << s1.vec_d[i] << " ";
    cout << endl;
#pragma endregion

#pragma region Ref
    test_w_ref(s2, my_arr2);
    cout << "\nTest with Ref.\n";
    cout << "Array:\n";
    for (int i = 0; i < 5; i++)
        cout << my_arr2[i] << " ";
    cout << endl;

    cout << "Struct:\n";
    cout << "dim: " << s2.get_dim() << endl;

    cout << "a: " << s2.a << "\n";

    cout << "b: ";
    for (int i = 0; i < 3; i++)
        cout << s2.b[i] << " ";
    cout << endl;

    cout << "c: ";
    for (int i = 0; i < s2.get_dim(); i++)
        cout << s2.c[i] << " ";
    cout << endl;

    cout << "vec_i: ";
    for (int i = 0; i < s2.vec_i.size(); i++)
        cout << s2.vec_i[i] << " ";
    cout << endl;

    cout << "vec_d: ";
    for (int i = 0; i < s2.vec_d.size(); i++)
        cout << s2.vec_d[i] << " ";
    cout << endl;
#pragma endregion

    return 0;
}

Here is the output:

Before calling functions
Array:
1 2 3 4 5
Struct:
dim: 2
a: 0
b: 1 2 3
c: -6.27744e+66 -6.27744e+66
vec_i:
vec_d:

Test with Val.
Array:
1 3 5 7 9
Struct:
dim: 2
a: 0
b: 1 2 3
c: 1000 1001
vec_i:
vec_d:

Test with Ref.
Array:
1 3 5 7 9
Struct:
dim: 2
a: 10
b: 100 200 300
c: 1000 1001
vec_i: 50 60
vec_d: 10000 20000

Finally, from this:

The mechanism by which the array is passed into the function (a pointer to the first element of the array is passed to the function) functions similarly to pass-by-reference

That is, any changes you make to array within the function mutates the original array even if you don't explicitly pass in a reference to it.

In case, you want to pass an array into a function and protect it from mutations, you may manually make a copy of it and pass the copy to the function. Alternatively, you may use containers wrapping an array, e.g std::array and std::vector. [Source]

Ailurophobe answered 8/12, 2023 at 18:32 Comment(0)
P
0

In C++, types declared as a class, struct, or union are considered "of class type". These are passed by value or you can say a copy using copy constructor is passed to the functions. This is pretty evident when we implement binary trees wherein you almost always have a Node * type of param in the recursive function acting on the binary tree. This is so as to facilitate modification of that node. If the node were to be passed as is (i.e not being a pointer type), the modifications to the nodes would have been to the local copy. Even in the case of vectors, while passing a copy of vectors is passed to the functions, to avoid which we use a reference &.

Pornocracy answered 3/8, 2019 at 12:57 Comment(0)
B
-6

C++ passes arguments that are no pointers (int*) or references (int&) by value. You cannot modify the var of the calling block in the called function. Arrays are pointers.

Boodle answered 19/1, 2014 at 10:17 Comment(10)
C++ also passes pointer by value. There is no magical exception.Juliannjulianna
In C++ terminology, the fact that a parameter type is a pointer doesn't influence whether its by value or by reference. If it's just a pointer, it's by value. If it's a reference to a pointer, it's by reference.Euratom
What I meant was, the argument is declared as a pointer or a reference. Sorry for my bad english. I understood the question in a sense of "Can I modify the passed var within the called function.Boodle
If the argument is declared as a pointer, the pointer is passed by value. If it is declared as reference to pointer, it is passed by reference. Also, arrays aren't pointers.Juliannjulianna
juanchopanza - arrays degenerate to pointers. See, for example, #4224117.Urus
@noloader: A value of array type is implicitly converted to a value of pointer type in some, but not all, contexts.Homeland
@Juliannjulianna C++ also passes pointer by value. But thats the pass by reference in itself.Supertax
@aLearner Sorry, I don't understand the second sentence in your comment.Juliannjulianna
@Juliannjulianna I mean to say that in pass by reference also we pass the pointer by value if we are passing the address of a variable. In fact we always pass pointer by value.Supertax
@aLearner I think you're using C terminology. In C++, pointers are not references. When we "pass by reference" we pass a reference, not a pointer.Juliannjulianna

© 2022 - 2025 — McMap. All rights reserved.