Are there benefits of passing by pointer over passing by reference in C++?
Solution 1
A pointer can receive a NULL parameter, a reference parameter can not. If there's ever a chance that you could want to pass "no object", then use a pointer instead of a reference.
Also, passing by pointer allows you to explicitly see at the call site whether the object is passed by value or by reference:
// Is mySprite passed by value or by reference? You can't tell
// without looking at the definition of func()
func(mySprite);
// func2 passes "by pointer" - no need to look up function definition
func2(&mySprite);
Solution 2
Passing by pointer
- Caller has to take the address -> not transparent
- A 0 value can be provided to mean
nothing
. This can be used to provide optional arguments.
Pass by reference
- Caller just passes the object -> transparent. Has to be used for operator overloading, since overloading for pointer types is not possible (pointers are builtin types). So you can't do
string s = &str1 + &str2;
using pointers. - No 0 values possible -> Called function doesn't have to check for them
- Reference to const also accepts temporaries:
void f(const T& t); ... f(T(a, b, c));
, pointers cannot be used like that since you cannot take the address of a temporary. - Last but not least, references are easier to use -> less chance for bugs.
Solution 3
I like the reasoning by an article from "cplusplus.com:"
Pass by value when the function does not want to modify the parameter and the value is easy to copy (ints, doubles, char, bool, etc... simple types. std::string, std::vector, and all other STL containers are NOT simple types.)
Pass by const pointer when the value is expensive to copy AND the function does not want to modify the value pointed to AND NULL is a valid, expected value that the function handles.
Pass by non-const pointer when the value is expensive to copy AND the function wants to modify the value pointed to AND NULL is a valid, expected value that the function handles.
Pass by const reference when the value is expensive to copy AND the function does not want to modify the value referred to AND NULL would not be a valid value if a pointer was used instead.
Pass by non-cont reference when the value is expensive to copy AND the function wants to modify the value referred to AND NULL would not be a valid value if a pointer was used instead.
When writing template functions, there isn't a clear-cut answer because there are a few tradeoffs to consider that are beyond the scope of this discussion, but suffice it to say that most template functions take their parameters by value or (const) reference, however because iterator syntax is similar to that of pointers (asterisk to "dereference"), any template function that expects iterators as arguments will also by default accept pointers as well (and not check for NULL since the NULL iterator concept has a different syntax).
What I take from this is that the major difference between choosing to use a pointer or reference parameter is if NULL is an acceptable value. That's it.
Whether the value is input, output, modifiable etc. should be in the documentation / comments about the function, after all.
Solution 4
Allen Holub's "Enough Rope to Shoot Yourself in the Foot" lists the following 2 rules:
120. Reference arguments should always be `const`
121. Never use references as outputs, use pointers
He lists several reasons why references were added to C++:
- they are necessary to define copy constructors
- they are necessary for operator overloads
const
references allow you to have pass-by-value semantics while avoiding a copy
His main point is that references should not be used as 'output' parameters because at the call site there's no indication of whether the parameter is a reference or a value parameter. So his rule is to only use const
references as arguments.
Personally, I think this is a good rule of thumb as it makes it more clear when a parameter is an output parameter or not. However, while I personally agree with this in general, I do allow myself to be swayed by the opinions of others on my team if they argue for output parameters as references (some developers like them immensely).
Solution 5
Clarifications to the preceding posts:
References are NOT a guarantee of getting a non-null pointer. (Though we often treat them as such.)
While horrifically bad code, as in take you out behind the woodshed bad code, the following will compile & run: (At least under my compiler.)
bool test( int & a)
{
return (&a) == (int *) NULL;
}
int
main()
{
int * i = (int *)NULL;
cout << ( test(*i) ) << endl;
};
The real issue I have with references lies with other programmers, henceforth termed IDIOTS, who allocate in the constructor, deallocate in the destructor, and fail to supply a copy constructor or operator=().
Suddenly there's a world of difference between foo(BAR bar) and foo(BAR & bar). (Automatic bitwise copy operation gets invoked. Deallocation in destructor gets invoked twice.)
Thankfully modern compilers will pick up this double-deallocation of the same pointer. 15 years ago, they didn't. (Under gcc/g++, use setenv MALLOC_CHECK_ 0 to revisit the old ways.) Resulting, under DEC UNIX, in the same memory being allocated to two different objects. Lots of debugging fun there...
More practically:
- References hide that you are changing data stored someplace else.
- It's easy to confuse a Reference with a Copied object.
- Pointers make it obvious!
Related videos on Youtube
Matt Pascoe
I am currently working for CME Group, Inc. as a QA Analyst 2. I run performance testing on their electronic trading platform called Globex. Before working for CME Group, Inc. I was a student at DeVry University studying for my Bachelors of Science in Computer Information Systems. I have worked with C++ for a number of years and am starting to dable in Java here and there. Also, because of the nature of my job I occasionally have to pick up a scripting language to help automate tasks.
Updated on May 14, 2020Comments
-
Matt Pascoe about 4 years
What are the benefits of passing by pointer over passing by reference in C++?
Lately, I have seen a number of examples that chose passing function arguments by pointers instead of passing by reference. Are there benefits to doing this?
Example:
func(SPRITE *x);
with a call of
func(&mySprite);
vs.
func(SPRITE &x);
with a call of
func(mySprite);
-
Martin York over 5 yearsDon't forget about
new
to create a pointer and the resulting issues of ownership.
-
-
Greg Rogers over 15 yearsThats both an advantage and a disadvantage. Many APIs use NULL pointers to mean something useful (ie NULL timespec wait forever, while the value means wait that long).
-
foraidt over 15 years@Brian: I don't want to be nit-picking but: I would not say one is guaranteed to get an instance when getting a reference. Dangling references are still possible if the caller of a function de-references a dangling pointer, which the callee cannot know.
-
Johannes Schaub - litb over 15 yearssometimes you can even gain performance by using references, since they don't need to take any storage and don't have any addresses assigned for themself. no indirection required.
-
Konrad Rudolph over 15 yearsPrograms which contain dangling references are not valid C++. Therefore, yes, the code can assume that all references are valid.
-
rmeador over 15 yearsI can definitely dereference a null pointer and the compiler won't be able to tell... if the compiler can't tell it's "invalid C++", is it really invalid?
-
Steve Jessop over 15 yearsMy stance in that argument is that if the function name makes it totally obvious, without checking the docs, that the param will be modified, then a non-const reference is OK. So personally I'd allow "getDetails(DetailStruct &result)". A pointer there raises the ugly possibility of a NULL input.
-
Steve Jessop over 15 yearsYes, it's invalid even if the compiler can't tell. Merely creating a dangling reference is specified to result in undefined behaviour. You can (well, you have no choice really) write code on the assumption that the program is in a defined state.
-
Steve Jessop over 15 yearsSo to be nit-picky one could say "assuming that the program state isn't already FUBARed, you're guaranteed an instance", instead of "you're guaranteed an instance". A dangling reference is an example of a FUBARed program state, but it should go without saying that your caller obeys the rules.
-
David Rodríguez - dribeas over 15 yearsThis is misleading. Even if some do not like references, they are a important part of the language and should be used as that. This line of reasoning is like saying don't use templates you can always use containers of void* to store any type. Read answer by litb.
-
Michael Burr over 15 yearsI don't see how this is misleading - there are times when references are required, and there are times when best practices might suggest not using them even if you could. The same can be said for any feature of the language - inheritance, non-member friends, operator overloading, MI, etc...
-
Michael Burr over 15 yearsBy the way, I agree that litb's answer is very good, and is certainly more comprehensive than this one - I just elected to focus on discussing a rationale for avoiding using references as output parameters.
-
Johannes Schaub - litb over 15 yearsthat's not the problem of the function or references. you are breaking language rules. dereferencing a null pointer by itself is already undefined behavior. "References are NOT a guarantee of getting a non-null pointer.": the standard itself says they are. other ways constitute undefined behavior.
-
paercebal over 15 yearsI agree with litb. While true, the code you are showing us is more sabotage than anything else. There are ways to sabotage anything, including both the "reference" and "pointer" notations.
-
paercebal over 15 yearsIncomplete answer. Using pointers won't authorize uses of temporary/promoted objects, nor the use of pointed object as stack-like objects. And it will suggest that the argument can be NULL when, most of the time, a NULL value should be forbidden. Read litb's answer for a complete answer.
-
Mr.Ree over 15 yearsI did say it was "take you out behind the woodshed bad code"! In the same vein, you can also have i=new FOO; delete i; test(*i); Another (unfortunately common) dangling pointer/reference occurrence.
-
Frerich Raabe over 14 yearsPassing by pointer also raises the 'Is ownership transferred or not?' question. This is not the case with references.
-
Londerson Araújo over 13 yearsThis rule is used in google c++ style guide: google-styleguide.googlecode.com/svn/trunk/…
-
Sylvain Defresne over 13 yearsYou should probably add that it is cleaner to use pointer when there is ownership transfer, or for registering callbacks (item that must survive the current stack frame).
-
William Pursell over 12 yearsI disagree with "less chance for bugs". When inspecting the call site and the reader sees "foo( &s )" it is immediately clear that s may be modified. When you read "foo( s )" it is not at all clear if s may be modified. This is a major source of bugs. Perhaps there is less chance of a certain class of bugs, but overall, passing by reference is a huge source of bugs.
-
Gbert90 about 12 yearsWhat do you mean by "transparent" ?
-
Michael J. Davenport almost 12 years@Gbert90, if you see foo(&a) at a call site, you know foo() takes a pointer type. If you see foo(a), you don't know whether it takes a reference.
-
Lightness Races in Orbit over 11 yearsThe second function call used to be annotated
func2 passes by reference
. Whilst I appreciate that you meant it passes "by reference" from a high-level perspective, implemented by passing a pointer at a code-level perspective, this was very confusing (see stackoverflow.com/questions/13382356/…). -
Happy Green Kid Naps over 11 years@MichaelJ.Davenport -- that doesn't seem to be the context in which "transparent" is used in Johannes' post.
-
Michael J. Davenport over 11 years@HappyGreenKidNaps - For my benefit and that of Gbert90, could you elaborate?
-
Happy Green Kid Naps over 11 years@MichaelJ.Davenport -- in your explanation, you suggest "transparent" to mean something along the lines of "obvious that caller is passing a pointer, but not obvious that caller is passing a reference". In Johannes' post, he says "Passing by pointer -- Caller has to take the address -> not transparent" and "Pass by reference -- Caller just passes the object -> transparent" -- which is nearly opposite of what you say. I think Gbert90's question "What do you mean by "transparent"" is still valid.
-
deworde over 11 yearsI just don't buy this. Yes, you pass in a pointer, so therefore it must be an output parameter, because what's pointed to can't be const?
-
Jon about 11 yearsTransparency means "easy for others to see what actions are performed" (wikipedia). An address-of operator at the call site makes it more transparent to readers that this argument may be modified. I've edited the answer, let's see if the change is accepted.
-
Brandon Ling over 10 yearsAgreed, when I was reading Adam's comment it made sense regarding transparent then when I came to this answer it just confused me because it is backwards. Just giving an outsiders point of view.
-
Madbreaks about 10 years+1, great answer. Although I will admit I was momentarily confused by your use of
->
in your answer...we are talking about pointers here after all. ;) -
David Stone almost 9 yearsRegardless of what you do with the reference returned, the moment you say
*i
, your program has undefined behavior. For instance, the compiler can see this code and assume "OK, this code has undefined behavior in all code paths, so this entire function must be unreachable." Then it will assume that all branches that lead to this function are not taken. This is a regularly performed optimization. -
Jon Wheelock over 8 yearsDon't we have this passing reference in C? I am using codeblock (mingw) latest version and in that selecting a C project. Still passing by reference (func (int& a)) works. Or is it available in C99 or C11 onwards?
-
Adam Rosenfield over 8 years@JonWheelock: No, C does not have pass-by-reference at all.
func(int& a)
is not valid C in any version of the standard. You're probably compiling your files as C++ by accident. -
Jon Wheelock over 8 yearsYou are right. My file name was .cpp and after changing to .c it gave error.
-
binaryguy over 8 yearsYes, for me the NULL related terms are the main concerns here. Thx for quoting..
-
Marco Sulla almost 8 years@Jon and the others: I suppose Johannes is talking about interface transparency. It means that he interface masks the complexity of the engine below. If you pass the object directly to the function, the function could get reference or get the value, you can't know, but the interface will remain the same, and it's more simple for the end user. See en.wikipedia.org/wiki/…
-
Earth Engine over 7 yearsI think there is a very important exception of those rules: the
swap
function plays a really important role in the copy-swap idiom, but without declaring its parameters as non-const references, there is no way to do what it intended to do. Using pointers here will be troublesome and breaks its exception-free promise easily. -
ihodonald about 7 yearsDon't you mean "null argument?" The parameter is in the function declaration.
-
Arkady Godlin about 6 yearsas Scott Meyers said in his book "More Effective C++" in page 10 regarding make reference refer to dereferenced null pointer "well this is eveil, pure and simple. The results are undefined and people who write this kind of code should be shunned untill they agree to cease and desist"
-
Ken Jackson over 5 yearsA reference parameter can receive NULL, @AdamRosenfield. Pass it as
func(*NULL)
. Then inside the function, test withif (&x == NULL)
. I suppose this looks ugly, but the difference between pointer and reference parameters is syntactic sugar. -
Ken Jackson over 5 yearsNo, @DavidStone, the
test(*i)
statement does not dereference NULL. NULL would only be dereferenced if the function accessed parametera
without the&
operator. Perhaps it's assumed to be impossible to pass NULL just to avoid the need to write more bulletproof code. -
David Stone over 5 years@KenJackson: eel.is/c++draft/dcl.ref#5 "A reference shall be initialized to refer to a valid object or function. [ Note: In particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the “object” obtained by indirection through a null pointer, which causes undefined behavior."
-
Ken Jackson over 5 yearsThe clause of the rule you cited, @DavidStone, seems to limit the propriety of what the programmer may do, rather than specify what the compiler shall do. That's language use, not implementation so one wonders if it's in scope. Regardless, in the example given, NULL is not dereferenced.
-
Adam Rosenfield over 5 years@KenJackson: Nope, that's Undefined Behavior to dereference a null pointer
-
zjyhjqs about 2 years@FrerichRaabe Address could be obtained by reference though the weird semantic is a signal to some dangerous behaviours. But in a well-defined system with
RAII
it shouldn't be a problem..