Quote:There was recently a thread on this forum in which a few people seemed fairly adamant that references were preferable to pointers when passing mutable parameters by reference, so a function can modify them. I think there's probably some good grounds for their opinions, so I'm interested to know why.
There are a few reasons, and I'll go into them a bit further on. Passing data members that are modified by referance is mostly just for conformance however, when you're passing all members that don't get modified by constant referance, rather than by value. Passing by constant referance is a hell of a lot better than passing by value. Passing data members that are in fact modified inside a function by non-constant referance just kind of follows from that.
Quote:The extra ampersand makes it clear when I (or anyone else) scan the code in 3 months' time that intVal is likely to be getting modified by the function.
If you adhere to passing by constant referance for all parameters that are not modified in a function, and passing by non-constant referance for all parameters that are, the function signature tells anyone using it whether a parameter will or will not be modified within that function, which acts as a method of self-documentation as well.
Quote:This is a fairly minor preference; there's doesn't seem to be any big technical advantage to either pointer or reference. References can't be null, but that seems as much a detriment as a benefit. So, given that I'm not particularly attached to either pointer or reference for this purpose, I'm curious as to why someone would hold a strong opinion on the subject. What am I missing?
It seems you are missing the wonders of passing by constant referance. Consider this example below:
int Foo(int val1, int val2){ return val1 * val2;}
This simple function takes two parameters by value. It doesn't modify these parameters anywhere in the function, it just makes a calculation based on their values. When passing these values to the function however, copies of them have to be made, which are local to the scope of the Foo function, and are destroyed when it exits. This may seem minor for a few integers, but when you're passing classes around with complecated constructors, large numbers of data members, or large memory blocks allocated to them, you'll be wasting a lot of time creating and deteting copies of these objects when you pass them to functions, and thrashing your memory in the process. Instead, you can pass them by constant referance:
int Foo(const int& val1, const int& val2){ return val1 * val2;}
This will not create the temporary copies. Instead, the original versions of the parameters will be referanced from within the function. This can lead to a major increase in performance over passing by value, as well as avoid errors from someone not implementing a copy constructor. If a class for example allocates a block of memory for use, which is freed in the destructor, but you have not provided a copy constructor to create a deep copy of these members, by allocating a new buffer and copying the contents into it, then when the copy is deleted, it will free the buffer that is held by the original object. This won't manifest itself immediately, and it'll be a real pain in the ass to track down if it happens.
The fact that you're passing by constant referance, prevents the function from modifying that parameter within the function (casting voodoo notwithstanding). You know it will not be modified, and you can rely on that being the case, rather than just trusting the guy who wrote the function stuck to the conventions.
You probably pass a pointer when you're throwing around large classes currently, but that has some disadvantages. First of all, I have no way of knowing for sure if that parameter will be modified within the function. Second, inside the function, I have to worry about if I was passed a valid pointer. Third, the syntax is different. You can get some ugly looking stuff with pointers when you want to use operators on the thing they referance. You often end up with things like (*pointer)++ or the like.
Passing by referance for parameters that will be modified, and constant referance for ones that won't, is just better in general. Not only are there practical reasons like the ones I've listed here, it makes it easier to proof check and enforce design models too, through const correctness, which this is a part of.