10

My teacher in c++ told me that call by reference should only be used if I'm not going to change anything on the arrays inside the function. I have some really big vectors that I'm passing around in my program. All the vectors will be modified inside the functions. My matrices are of sizes about [256*256][256][50]...

Is there some particular reason not to use call-by reference here?

AFAIK call by reference should be way faster and consume less memory?

klew
  • 14,837
  • 7
  • 47
  • 59
  • 3
    Maybe your teacher meant "pass by **const** reference should only be used if you're not going to change any of the data inside the function." – Dan Feb 16 '10 at 14:31
  • Nope, he did not. He told us that it is a rule of thumb to only use call-by-reference if you're not going to change anything. I see now from the answers below that even the teachers don't always now what they are talking about. –  Feb 16 '10 at 14:38
  • You're right. Teachers don't always know what they're talking about. And sometimes they do know, but accidentally misspeak. Or sometimes, they say the right thing, and students mishear them. Don't rule out the last option. – jalf Feb 16 '10 at 18:33
  • @jalf Heh, actually this time, I can rule out the last option since I can read his slides online and the above statement is found in them. However this forum is about programming so lets leave the teacher discussion for another forum... –  Feb 17 '10 at 10:11

11 Answers11

8

Besides all common discussions on when and how to pass by possibly const reference for non-primitive types, arrays are quite special here.

Due to backwards compatibility with C, and there due to your specific problem: arrays can be huge, arrays are never really passed by value in either C or C++. The array will decay into a pointer to the first element, so when you write:

void foo( type array[100] );

The compiler is actually processing:

void foo( type *array );

Regardless of what the size of the array is (two common pitfalls there: trusting that array is an array inside foo and believing that it will be guaranteed to be 100 elements on it.

Now, in C++ you can actually pass arrays by reference, but the reference must be of the concrete type of the array, that includes the size:

void foo_array( type (&array)[100] );

The funny syntax there is telling the compiler that the function will take an array of exactly 100 elements of type type. The advantage there is that the compiler can perform size checking for you:

// assuming 'type' is defined
int main() {
   type array0[99];
   type array1[100];

   foo( array0 );     // compiles, but if size=100 is assumed it will probably break
                      // equivalent to: foo( &array0[0] )
   // foo2( array0 ); // will not compile, size is not 100
   foo2( array1 );    // compiles, size is guaranteed to be 100
}

Now, the problem is that your function will only work for an array of exactly 100 elements, and in some cases, you might want to perform the same operation in different array sizes. The two solutions are: template the function in the size of the array which will provide a size-safe implementation for each used size --greater compile time and binary size, the template is compiled for every different size-- or using the pass-by-value syntax, which will make the array decay --not safe in size, that must be passed as extra argument, lesser compile time and binary size. A third option is combining both:

void foo( type *array, int size );
template <size_t N>
void foo( type (&array)[N] ) {
   foo( array, N );
}

In this case, while there will be one templated foo for each size, the compiler will most probably inline the call and the generated code would be equivalent to the caller providing the array and size. No extra computations needed and type safety for real arrays.

Now, pass-by-reference is very rarely used with arrays.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • 1
    Very, very useful answer, at least to me. I always wondered how to create size-safe arrays like that. Cool! (+1, obviously) – Gui Prá Feb 16 '10 at 14:41
5

My teacher in c++ told me that call by reference should only be used if I'm not going to change anything on the arrays inside the function.

It should be used when you are not changing something inside the function or you change things and want the changes to be reflected to the original array or don't care about the changes to be reflected in the original array.

It shouldn't be used if you don't want your function to change your original array (you need to preserve the original values after the call) and the callee function changes the values of the passed argument.

Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • 1
    It absolutely should be used with larger arrays, even if you don't want to change it. At that point you pass it by const reference and the compiler will keep you honest. – Xorlev Feb 16 '10 at 17:06
  • @Xorlev: Yeah. Did I say something else? I'm reading my answer but I can't quite get which part might get misinterpreted. It's saying the same thing. – Mehrdad Afshari Feb 16 '10 at 17:26
4

Your teacher is wrong. If you need to modify arrays, pass by reference is the way to go. If you don't want something modified, pass by const reference.

Richard Pennington
  • 19,673
  • 4
  • 43
  • 72
1

To prevent accidental changes, use pass-by-const-reference; that way, by default*, the passed-in array can't get changed by the called function.

* Can be overridden with const_cast.

C. K. Young
  • 219,335
  • 46
  • 382
  • 435
1

You can pass by reference if:

  1. you won't modify passed object
  2. you want to modify object and don't want to keep old object untouched

When you pass something by reference, then only pointer is passed to function. If you pass whole object then you need to copy it, so it will consume more cpu and memory.

klew
  • 14,837
  • 7
  • 47
  • 59
1

Hold on a second.. I'm scared at how people are answering this one. Arrays, as far as I remember, are always passed by reference.

void function(int array[])
{
    std::cout << array[0] << '\n';
}

// somewhere else..
int array[2] = { 1, 2 };
function(array); // No copy happens here; it is passed by reference

Further, you can't say the array argument is a reference explicitly, as that would be the syntax for creating an array of references (something that's not allowed).

void function(int &array[]) // error here
{ /* ... */ }

So what do you mean?

Further, many are saying that you should only do that if you modify the contents of the array inside the function. Then, what about reference-to-const?

void function(const int arr[])
{
    std::cout << arr[0] << '\n';
}

-- edit

Will somebody please point me out how to not pass an array by reference in C++?

-- edit

Oh, so you're talking about vectors. Okay, then the rules of thumb are:

  • Pass by reference only when you want to modify the contents of the vector.
  • Pass by reference-to-const whenever you can.
  • Pass by value only when the object in question is really, really small (like a struct containing an integer, for example), or when it makes sense to (can't think of a case out of the top of my head).

Did I miss something?

-- edit

  • In the case of plain C arrays, it's a good idea to pass them by reference (like in void function(int (&array)[100])) when you want to ensure that the array has a given definite size.

Thanks, dribeas.

Gui Prá
  • 5,559
  • 4
  • 34
  • 59
  • this confusion is probably coming from my question as I talk about arrays but I actually mean vectors... –  Feb 16 '10 at 14:13
  • They are not passed by reference, but rather decay into a pointer to the first element. The compiler will change the signature to `void foo( int *array )` and the calls to `foo( &array[0] )`. Then again you **can** pass an array by reference: `void foo( int (&array)[100] )`. The syntax is a little more obscure and the size must be explicitly stated (as it is part of the type) but you can do it. – David Rodríguez - dribeas Feb 16 '10 at 14:14
1

Generally speaking, objects should always be passed by reference. Otherwise a copy of the object will be generated and if the object is substantially big, this will affect performance.

Now if the method or function you are calling does not modify the object, it is a good idea to declare the function as follows:

void some_function(const some_object& o);

This will generate a compile error if you attempt to modify the object's state inside the function body.

Also it should be noted that arrays are always passed by reference.

Austin
  • 791
  • 1
  • 7
  • 14
0

Usually, in introductory courses, they tell you that so you don't accidentally change something you didn't want to.

Like if you passed in userName by reference, and accidentally changed it to mrsbuxley that probably would cause errors, or at the very least be confusing later on.

taylonr
  • 10,732
  • 5
  • 37
  • 66
0

I don't see any reason why you can't pass by reference. Alternatively you could pass pointers around, but I think pass by reference is better sometimes as it avoids null pointer exceptions.

If your teacher has suggested this as some kind of convention, then feel free to break it if it makes sense to. You can always document this in a comment above the function.

bramp
  • 9,581
  • 5
  • 40
  • 46
0

Our house style is to NEVER pass an object by value but to always pass a reference or const reference. Not only do we have data structures that can contain 100s of MB of data and pass by value would be an application killer, but also if we were passing 3D points and vectors by value the our applications would grind to a halt.

lilburne
  • 565
  • 1
  • 3
  • 10
0

It is always a good choice to pass object by reference but we need to be careful and first we have to decide what is our purpose/ purpose of our function?

You have to make a choice here, whether we are gonna only read the data of an object or modify it.

Suppose you got an interface like

void increament_value(int& a);

so in this you can modify value an object which we are passing, but it is a disaster when you passing your sensitive data, you might lose you original data and can not revert it, right?

so c++ provides you a functionality to not to change the value of an object whose reference you are passing to a function, and it is always a good choice to pass a const reference of an object for e.g.,

double get_discounted_amount(const double &amount,double discount){
    return (amount*discount/100);
}

This guarantees that your actual value of an object is not gonna change, but again it depends on purpose of your interface whether you wanna change it or only use(read) it

Hiren
  • 57
  • 1
  • 11