457

I understand the syntax and general semantics of pointers versus references, but how should I decide when it is more-or-less appropriate to use references or pointers in an API?

Naturally some situations need one or the other (operator++ needs a reference argument), but in general I'm finding I prefer to use pointers (and const pointers) as the syntax is clear that the variables are being passed destructively.

E.g. in the following code:

void add_one(int& n) { n += 1; }
void add_one(int* const n) { *n += 1; }
int main() {
  int a = 0;
  add_one(a); // Not clear that a may be modified
  add_one(&a); // 'a' is clearly being passed destructively
}

With the pointer, it's always (more) obvious what's going on, so for APIs and the like where clarity is a big concern are pointers not more appropriate than references? Does that mean references should only be used when necessary (e.g. operator++)? Are there any performance concerns with one or the other?

EDIT (OUTDATED):

Besides allowing NULL values and dealing with raw arrays, it seems the choice comes down to personal preference. I've accepted the answer below that references Google's C++ Style Guide, as they present the view that "References can be confusing, as they have value syntax but pointer semantics.".

Due to the additional work required to sanitise pointer arguments that should not be NULL (e.g. add_one(0) will call the pointer version and break during runtime), it makes sense from a maintainability perspective to use references where an object MUST be present, though it is a shame to lose the syntactic clarity.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
connec
  • 7,231
  • 3
  • 23
  • 26
  • It's clear that it may be modified when it's a non-const reference. A const reference, on the other hand, clearly states it can't be modified. They look the same on calling, but most of the time intellisense (or something similar) will tell you what's up, and you can deduce from that. Otherwise, you could just document your API ;) – Seb Holzapfel Aug 14 '11 at 17:12
  • 5
    It seems like you've already made your decision about which one to use when. Personally, I prefer to pass in the object that I'm acting on, whether or not I'm modifying it. If a function takes a pointer, that tells me that it's acting on pointers, i.e. using them as iterators in an array. – Benjamin Lindley Aug 14 '11 at 17:19
  • @Schnommus: It's only clear when you're looking at the method declaration, it's not always convenient when reading over code to look at the definition of every method called. – connec Aug 14 '11 at 18:26
  • @Benjamin: I tend to avoid pointer arithmetic in C++ as are clearer interfaces available to avoid it (STL containers etc.). – connec Aug 14 '11 at 18:28
  • @connec - I've never used an IDE without intellisense or something similar for anything serious - So I never really have to look in the header definition, VS just shows it to me when I type the function in.. – Seb Holzapfel Aug 14 '11 at 18:29
  • 1
    @Schnommus: Fair enough, I mostly use TextMate. Still, I think it's preferable that the meaning would be obvious from a glance. – connec Aug 14 '11 at 18:33
  • @connec: As do I, which is why I'm left with almost no reason to ever write a function that takes pointers. – Benjamin Lindley Aug 14 '11 at 18:38
  • @Benjamin: Hehe, I wouldn't use them unless it was necessary :) The situation I'm looking at at the moment is a Tree and the `add_child` method (e.g. `node1.add_child(&node2)`), the child must be passed by reference to update its parent. I suppose I could make two functions (`add_child` and `set_parent`) but that seems a bit bloated. – connec Aug 14 '11 at 19:14
  • 6
    What about `add_one(a);` is unclear that `a`'s going to be modified? It says right in the code: *add one*. – GManNickG Aug 14 '11 at 19:52
  • 44
    @connec: The Google C++ style guide is not considered a good C++ style guide. It is a style guide for working with Google's old C++ code base (i.e. good for their stuff). Accepting an answer based on that is not helping anybody. Just reading your comments and explanation you came to this question with an already set opinion and are just looking for other people to confirm your view. As a result you are basing the question and answer to what you want/expect to hear. – Martin York Aug 14 '11 at 22:23
  • @Martin: I've changed my answer now, though from my perusal of it they tended to indicate when it was a compatibility decision (e.g. with exceptions), which they did not in this case (instead highlighting the syntax/semantics inconsistency, which I still feel is a valid point). – connec Aug 14 '11 at 22:26
  • 1
    This is simply fixed by naming the method `addOneTo(...)`. If that's not what you want to do, just look at the declaration. – stefan May 19 '13 at 12:00
  • TrollTech seems to support your view - http://doc.qt.digia.com/qq/qq13-apis.html#pointersorreferences – BlueSilver Feb 28 '14 at 14:19

17 Answers17

378

Use references wherever you can, and pointers wherever you must.

Avoid pointers until you can't.

The reason is that pointers make things harder to follow/read, less safe and far more dangerous manipulations than any other constructs.

So the rule of thumb is to use pointers only if there is no other choice.

For example, returning a pointer to an object is a valid option when the function can return nullptr in some cases and it is assumed it will. That said, a better option would be to use something similar to std::optional (requires C++17; before that, there's boost::optional).

Another example is to use pointers to raw memory for specific memory manipulations. That should be hidden and localized in very narrow parts of the code, to help limit the dangerous parts of the whole code base.

In your example, there is no point in using a pointer as an argument because:

  1. if you provide nullptr as the argument, you're going in undefined-behaviour-land;
  2. the reference attribute version doesn't allow (without easy-to-spot tricks) the problem with 1.
  3. the reference attribute version is simpler to understand for the user: you have to provide a valid object, not something that could be null.

If the behaviour of the function would have to work with or without a given object, then using a pointer as an attribute suggests that you can pass nullptr as the argument and it is fine for the function. That's kind of a contract between the user and the implementation.

user
  • 1,220
  • 1
  • 12
  • 31
Klaim
  • 67,274
  • 36
  • 133
  • 188
  • 60
    I'm not sure that pointers make anything harder to read? It's a fairly simple concept and makes it clear when something is likely to be modified. If anything I'd say it's harder to read when there's no indication of what's happening, why should `add_one(a)` not return the result, rather than set it by reference? – connec Aug 14 '11 at 18:21
  • 49
    @connec: If `add_one(a)` is confusing, then that is because it is improperly named. `add_one(&a)` would have the same confusion, only now you might be incrementing the pointer and not the object. `add_one_inplace(a)` would avoid all confusion. – Nicol Bolas Aug 14 '11 at 22:19
  • 28
    One point, references can refer to memory that can go away just as easily as pointers can. So they are not necessarily any safer than pointers. Persisting and passing references can be just as dangerous as pointers. – Doug T. Aug 15 '11 at 00:44
  • 2
    connec> Simple construct, easy to understand alone, but hard to follow in context. When you use a pointer in C++, if you don't add tons of asserts, you have only few guarantees about what is pointed. – Klaim Aug 15 '11 at 07:44
  • Will add in C++ use references whenever possible and rely on the exception model to kick you out of any undefined situations. Pointers should really only be used when implementing specialized data-structures or addressing an array. – user805547 Dec 05 '12 at 04:10
  • 2
    @user805547 Actually it is currently recommended to use pointers as "not owning" pointers because it's less expensive than other alternatives. A more explicit standard pointer type would be useful to make it more clear but right now it's ok to use raw pointer to express absence of ownership, at least in a modern-c++ code base. – Klaim Dec 05 '12 at 13:25
  • 3
    Well... importing a full hundreds-of-megabytes library just to have an "optional" object when we already have one... that's a bit of an exaggeration I think. Pointers have their use as well. –  Aug 26 '13 at 21:51
  • @H2CO3 It's not about "pointers" in general it's more about "raw pointers" which are just too dangerous, but still sometime necessary. There is now a proposal to add other smart pointers to C++, like the dumbest smart pointer which would replace most "non-owning" pointers: http://isocpp.org/files/papers/n3740.pdf – Klaim Aug 29 '13 at 19:00
  • 9
    @Klaim I meant raw pointers. I meant that C++ has pointers, `NULL` and `nullptr`, and it has them for a reason. And it's not a well-considered or even realistic advice to give that "never use pointers", and/or "never use NULL, always use `boost::optional`". That's just insane. Don't get me wrong, raw pointers are needed less often in C++ than in C, but still, they are useful, they are not as "dangerous" as some C++ people like to claim (that's an exaggeration too), and again: when it's easier to just use a pointer and `return nullptr;` to indicate a missing value... Why import the whole Boost? –  Aug 29 '13 at 19:07
  • 1
    @H2CO3 First, std::optional have been voted in for C++14 - this is not about boost specifically, other implementations exists and you can DIY too. Second, all these advices are what the very people from the standard are saying, and they have strong arguments for them. Third, I didn't say to always use optional instead of pointers, I said it's an option (for small return types in particular). There are tons of other options that allows avoiding pointers with no costs, depending on the situation, and that helps a lot documenting the code, making it more maintainable. I got a last point... – Klaim Aug 29 '13 at 22:12
  • 1
    @H2CO3 Fourth, I do not know at all your experience with C++ and really I don't want to be unrespectful, but saying that '"pointers are dangerous" is an exageration' suggests to me that maybe you never had experience with a big code base that is full of pointers. If you did (and even in smaller code bases) then you know the problem of not knowing if a pointer is owning the data, if there is a special way of destroying that data, and what to do when there is an exception occuring (leak). – Klaim Aug 29 '13 at 22:19
  • 1
    @H2CO3 Last thing: Saying pointers are not dangerous is quite bold and undefendable assertion today. Even if sometime, we just can't avoid them. If you didn't already do it, I suggest reading the recommanded C++ books proposed on the related SO question, they all state what I'm saying here. Basically if you don't agree, you'll have to provide arguments against those given by the experts in C++ who wrote these books and built the current standard (which avoids pointers as much as it can too). Final point: using NULL is considered bad practice in C++11. – Klaim Aug 29 '13 at 22:21
  • 6
    @Klaim "using NULL is bad practice" - now that's just ridiculous. And `if` is obsolete and one should use `while() { break; }` instead, right? Also, don't worry, I have seen and worked with large code bases, and yes, *if you are careless*, then ownership is a problem. Not if you stick to conventions, use them consistently and comment and document your code, though. But after all, I should just use C because I'm too dumb for C++, right? –  Aug 30 '13 at 05:34
  • 4
    @H2CO3 I think you misunderstood my statement: I meant that NULL is not recommanded because now we have nullptr. They basically do the same thing (setting a pointer to null is not bad...) but NULL can be used where int can be used, so that often is a problem as pointed there: http://thenewcpp.wordpress.com/2011/11/03/nullptr/ Also, don't extrapolate. Conventions and comments are good but they are not checked by the compiler. Errors are humans and assuming everybody will never be careless is totally incorrect. No, you're not dumb, but you don't seem to know the arguments behind my points. – Klaim Aug 30 '13 at 14:59
  • @Klaim Indeed, I thought that you suggested that the entire NULL pointer concept is obsolete. Of course there will always be careless people, but they will write code that doesn't make sense amyway. –  Aug 30 '13 at 15:16
  • 3
    @H2CO3 Actually no, these careless person are you and me, anyone, because there is no way anyone will not make errors. – Klaim Aug 30 '13 at 19:24
  • @H2CO3 If you didn't already watch it, you might want to watch http://channel9.msdn.com/Events/GoingNative/2013 - at this time only the first day occured but they already explained all day what I was saying in a more complete manner. In particular the STL talk and Sean's talk. I hope it is clearer than my comments here for you to see my points. – Klaim Sep 05 '13 at 12:44
  • 10
    @NicolBolas hmmmm `add_one_inplace(a)` does not look better IMO. What if you had more paremeters? `add_and_check_inplace_inplace_notinplace_notinplace(a, b, c, d)`? – mip Oct 14 '14 at 18:42
  • @GBlomqvist: Return types are not obvious from looking at the function call. The caller could be discarding the return. Whereas a name is *always* visible. – Nicol Bolas Nov 29 '17 at 21:05
  • @NicolBolas Sorry, that part was directed to user doc, my bad. I do agree that good names are vital, just wanted to add that a function's return type may say a lot about the function. However, it's true that the return type is not obvious from looking at the function call, good point. – user_ Nov 29 '17 at 22:43
79

The performances are exactly the same, as references are implemented internally as pointers. Thus you do not need to worry about that.

There is no generally accepted convention regarding when to use references and pointers. In a few cases you have to return or accept references (copy constructor, for instance), but other than that you are free to do as you wish. A rather common convention I've encountered is to use references when the parameter must refer an existing object and pointers when a NULL value is ok.

Some coding convention (like Google's) prescribe that one should always use pointers, or const references, because references have a bit of unclear-syntax: they have reference behaviour but value syntax.

Junaith
  • 3,298
  • 24
  • 34
Andrea Bergia
  • 5,502
  • 1
  • 23
  • 38
  • It seems the disallowing of NULL with references is the only semantic difference between `&` and `* const`. Also if Google's doing it it must be right, right? :) – connec Aug 14 '11 at 18:12
  • 13
    Just to add a little to this, Google's [style guide says](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Reference_Arguments) that input parameters to functions should be const references and outputs should be pointers. I like this because it makes it very clear when you read a function signature what is an input and what's an output. – Dan Aug 14 '11 at 18:43
  • 1
    @connec: try coding against the AdWords API... it will completely change the way you think about Google. – tdammers Aug 14 '11 at 19:28
  • 51
    @Dan: The Google style guide is for Google's old code, and shouldn't be used for modern coding. In fact, it's a rather *bad* coding style for a new project. – GManNickG Aug 14 '11 at 19:53
  • 13
    @connec: Let me put it this way: null is a *perfectly valid* pointer value. Anywhere there's a pointer, I can give it the value null. Ergo your second version of `add_one` is *broken*: `add_one(0); // passing a perfectly valid pointer value`, kaboom. You need to check if it's null. Some people will retort: "well I'll just document that my function doesn't work with null". That's fine, but then you defeat the purpose of the question: if you're going to look to the documentation to see if null is okay, *you'll also see the function declaration*. – GManNickG Aug 14 '11 at 19:57
  • 9
    If it were a reference you'd see that to be the case. Such a retort misses the point though: References enforce *on a language level* that it refers to an existing object, and not possibly null, while pointers have no such restriction. I think it's clear that language-level enforcement is more powerful and less error-prone than documentation-level enforcement. Some will try to retort to this by saying: "Look, null reference: `int& i = *((int*)0);`. This isn't a valid retort. *The issue in the previous code lies with the pointer use, not with the reference*. References are never null, period. – GManNickG Aug 14 '11 at 19:59
  • 13
    Hello, I saw lack of language lawyers in the comments so let me remedy: references are *usually* implemented by pointers but the standard says no such thing. An implementation using some other mechanism would be 100% complaint. – Andreas Bonini Aug 14 '11 at 21:42
  • 5
    I disagree that there is no accepted convention. Always use references unless you need to convey the non existence of an object then you pass an empty smart pointer. You **practically never pass** a pointer in C++. Some may argue theat array are passed by pointer. Again I would disagree and say in C++ you should be passing a reference to a standard container (or more preferably two iterators). Only C passes arrays by pointer. – Martin York Aug 14 '11 at 22:14
  • @GMan: that's certainly a good point... it's a shame to have to trade off syntactic clarity though :( I'm still a little torn, in most situations it's obvious the argument shouldn't be null (in my case, it makes no sense to say add_child(NULL), though it would break everything if you did), but I suppose from a maintainability perspective the most robust approach should be preferred. I'm steadily learning why so many people think C++ is such a mess of a language xD – connec Aug 14 '11 at 22:14
  • 5
    @connec: If you think that then you are talking to the people who do not understand C++. Its a big complex language. But at its heart the beauty is in the simplicity of use. The problem is that programmers from other language bring expectations that C++ should work like their old language (C/Java developers spring to mind) and fall into big sticky holes when it does not. – Martin York Aug 14 '11 at 22:20
  • 2
    @connec : `it's a shame to have to trade off syntactic clarity though :(` : It's a rather personal viewpoint. By writting `foo(&bar)`, you are just passing... an address. Nothing more. Your own personal conventions says your `foo` will modify `bar`, but as far as I am concerned, reading that code, I'm only confused, and worried about what you are really doing with the address of the object (pointer arithmetics? deleting it?). You can't expect to use a function without knowing what it does with its parameters. And if you know what a function is doing, then you don't need the `&` thing. – paercebal Aug 15 '11 at 08:06
  • 2
    @connec : Now, C# has a `ref` and `out` parameter qualifiers. In some ways, it is clearer about what the function will do with the parameter (through if you are passing an object reference by `ref`, the info means nothing much). After months of writing C# code, `ref` and `out` is syntactic sugar I could live without in C#, and would dislike to have to use in C++. In the other end, I still dearly miss `friend` and `const`, my C# code being a lot less safe without them. Are you sure you are focusing on the important issue, here? – paercebal Aug 16 '11 at 07:52
  • @paercebal Who has time to read every function they use to know everything it does? In some cases, that's not even possible (if you're using a library sans source code). Being an effective programmer often involves making assumptions about behavior or narrowing the scope of how much you need to investigate. A function that takes a const reference helps cut down the extraneous work I'd otherwise have to do. – iheanyi Oct 24 '14 at 19:09
  • 1
    @iheanyi : A function has a contract, that is: What it does, what are its pre-condition and post-conditions. And you're right: The fact a parameter is passed by const ref is a very good hint. We agree on that. – paercebal Oct 25 '14 at 21:16
  • 1
    @paercebal What you state about `ref` and `out` is incorrect, they are most definitely not syntactic sugar. Parameters are passed differently. A reference parameter to a reference type is still a different behavior than a value parameter to a reference type. You can change what the reference refers to. As for it being syntactic sugar when passing it as an argument, that's also incorrect. On both IL and machine code level it's a different call. When reflecting, it's actually a different type (though `ref` and `out` are the same type), and therefore you can even overload methods on it. – Aidiakapi Jan 02 '15 at 12:51
  • @Aidiakapi : I guess you misunderstood me. I know fully well what `out` and `ref` are about in C#. Their mapping (or at least, `ref` mapping) in C++ are not so different (including when overloading). What I was saying was that, in C#, having to always add `out` or `ref` doesn't seem that positive *to me* (there are pros and cons), and I am very very happy to not have to do that in C++ when calling a function that takes a parameter by reference. – paercebal Jan 03 '15 at 13:12
  • 2
    @paercebal They actually are really different from C++ references. A value type parameter without `ref` would be similar to `MyClass` in C++. A reference type parameter **without** `ref` would be similar to `MyClass&`, a value type parameter with `ref` also maps to `MyClass&`. A reference type parameter with `ref` maps most closely to `MyClass*&`. Of course there are nuances. Most importantly however, is that in most cases when dealing with `class`es you'll be passing by reference, without marking it as `ref`. Similar to how references are passed in C++. – Aidiakapi Jan 03 '15 at 13:46
  • @Aidiakapi : Again, you're telling me nothing I didn't know (so I won't bother commenting your comment), and seem to be ignoring my point, that is: In C#, AT CALL SITE, you must add the `ref` (resp. `out`) keyword to your variable when the called function expects a `ref` (resp. `out`). In C++, AT CALL SITE, you need no specific keyword no matter if the parameter is passed by value or by reference. For me, the C# syntactic notation AT CALL SITE is interesting, but too cumbersome, going against generic notation. Thus, for me, the cons outweight the pros of the CALL SITE C#-style notation. – paercebal Jan 04 '15 at 14:01
  • 2
    @paercebal You're completely ignoring my point. AT THE CALL SITE, a pass by reference has the SAME SYNTAX as in C++, and does not require any syntactic notation. In C++ AT THE CALL SITE, you ALSO need special syntax to pass to a what in C# would be `ref` parameter. When dealing with reference types. The only time it differs is when passing a value type by reference. You stated two things "if you are passing an object reference by ref, the info means nothing much", and "`ref` and `out` is syntactic". Both are completely wrong. I'm just hoping you don't misinform people who read this. – Aidiakapi Jan 04 '15 at 14:15
  • Hi, do you mean that pass by reference actually uses a pointer that points to the variable being referenced? If so, then why we bother to create two different syntax that actually does the same thing? – Lake_Lagunita Sep 22 '15 at 06:23
  • @LeonloveKaren A compiler is free to implement references however it wants; it does not have to use pointers, and you should not concern yourself with the incidental fact that most compilers do. The only thing that matters is that pointers and references actually have really quite different semantics and strengths, as you'd see from reading the rest of this thread. – underscore_d Feb 26 '16 at 03:01
  • I like how succinctly you put it "they have reference behaviour but value syntax." –  Feb 27 '17 at 15:00
44

From C++ FAQ Lite -

Use references when you can, and pointers when you have to.

References are usually preferred over pointers whenever you don't need "reseating". This usually means that references are most useful in a class's public interface. References typically appear on the skin of an object, and pointers on the inside.

The exception to the above is where a function's parameter or return value needs a "sentinel" reference — a reference that does not refer to an object. This is usually best done by returning/taking a pointer, and giving the NULL pointer this special significance (references must always alias objects, not a dereferenced NULL pointer).

Note: Old line C programmers sometimes don't like references since they provide reference semantics that isn't explicit in the caller's code. After some C++ experience, however, one quickly realizes this is a form of information hiding, which is an asset rather than a liability. E.g., programmers should write code in the language of the problem rather than the language of the machine.

seaotternerd
  • 6,298
  • 2
  • 47
  • 58
Mahesh
  • 34,573
  • 20
  • 89
  • 115
  • 1
    I guess you could argue that if you're using an API you should be familiar with what it does and know whether or not the passed parameter is modified or not... something to consider, but I find myself agreeing with the C programmers (though I've little C experience myself). I'd add though that clearer syntax is of benefit to programmers as well as machines. – connec Aug 14 '11 at 18:16
  • 1
    @connec: Sure the C programmer have it correct for their language. But do not make the mistake of treating C++ as C. It is a completely different language. If you treat C++ as C you end up writing what is refereed to coequally as `C with class` (which is not C++). – Martin York Aug 14 '11 at 22:32
26

My rule of thumb is:

  • Use pointers for outgoing or in/out parameters. So it can be seen that the value is going to be changed. (You must use &)
  • Use pointers if NULL parameter is acceptable value. (Make sure it's const if it's an incoming parameter)
  • Use references for incoming parameter if it cannot be NULL and is not a primitive type (const T&).
  • Use pointers or smart pointers when returning a newly created object.
  • Use pointers or smart pointers as struct or class members instead of references.
  • Use references for aliasing (eg. int &current = someArray[i])

Regardless which one you use, don't forget to document your functions and the meaning of their parameters if they are not obvious.

Calmarius
  • 18,570
  • 18
  • 110
  • 157
19

Disclaimer: other than the fact that references cannot be NULL nor "rebound" (meaning thay can't change the object they're the alias of), it really comes down to a matter of taste, so I'm not going to say "this is better".

That said, I disagree with your last statement in the post, in that I don't think the code loses clarity with references. In your example,

add_one(&a);

might be clearer than

add_one(a);

since you know that most likely the value of a is going to change. On the other hand though, the signature of the function

void add_one(int* const n);

is somewhat not clear either: is n going to be a single integer or an array? Sometimes you only have access to (poorly documentated) headers, and signatures like

foo(int* const a, int b);

are not easy to interpret at first sight.

Imho, references are as good as pointers when no (re)allocation nor rebinding (in the sense explained before) is needed. Moreover, if a developer only uses pointers for arrays, functions signatures are somewhat less ambiguous. Not to mention the fact that operators syntax is way more readable with references.

bartgol
  • 1,703
  • 2
  • 20
  • 30
  • Thanks for the clear demonstration of where both solutions gain and lose clarity. I was initially in the pointer camp, but this makes a lot of sense. – Zach Beavon-Collin May 09 '16 at 00:45
14

Like others already answered: Always use references, unless the variable being NULL/nullptr is really a valid state.

John Carmack's viewpoint on the subject is similar:

NULL pointers are the biggest problem in C/C++, at least in our code. The dual use of a single value as both a flag and an address causes an incredible number of fatal issues. C++ references should be favored over pointers whenever possible; while a reference is “really” just a pointer, it has the implicit contract of being not-NULL. Perform NULL checks when pointers are turned into references, then you can ignore the issue thereafter.

http://www.altdevblogaday.com/2011/12/24/static-code-analysis/

Edit 2012-03-13

User Bret Kuhns rightly remarks:

The C++11 standard has been finalized. I think it's time in this thread to mention that most code should do perfectly fine with a combination of references, shared_ptr, and unique_ptr.

True enough, but the question still remains, even when replacing raw pointers with smart pointers.

For example, both std::unique_ptr and std::shared_ptr can be constructed as "empty" pointers through their default constructor:

... meaning that using them without verifying they are not empty risks a crash, which is exactly what J. Carmack's discussion is all about.

And then, we have the amusing problem of "how do we pass a smart pointer as a function parameter?"

Jon's answer for the question C++ - passing references to boost::shared_ptr, and the following comments show that even then, passing a smart pointer by copy or by reference is not as clear cut as one would like (I favor myself the "by-reference" by default, but I could be wrong).

Community
  • 1
  • 1
paercebal
  • 81,378
  • 38
  • 130
  • 159
  • 1
    The C++11 standard has been finalized. I think it's time in this thread to mention that most code should do perfectly fine with a combination of references, `shared_ptr`, and `unique_ptr`. Ownership semantics and in/out parameter conventions are taken care of by a combination of these three pieces and const'ness. There is almost no need for raw pointers in C++ except when dealing with legacy code and very optimized algorithms. Those areas where they are used should be as encapsulated as possible and convert any raw pointers to the semantically appropriate "modern" equivalent. – Bret Kuhns Sep 13 '12 at 13:42
  • 1
    A lot of the time smart pointers shouldn't be passed around, but should be tested for null-ness and then their contained object passed by reference. The only time you should actually pass a smart pointer is when you're transferring (unique_ptr) or sharing (shared_ptr) ownership with another object. – Luke Worth Feb 16 '15 at 07:42
  • @povman: I fully agree: If the ownership is not part of the interface (and unless it is about to be modified, it shouldn't be), then we should not pass a smart pointer as a parameter (or return value). The thing gets a bit more complicated when the ownership is part of the interface. For example, the Sutter/Meyers debate about how to pass a unique_ptr as parameter: by copy (Sutter) or by r-value reference (Meyers)? An antipattern relies on passing around a pointer to a global shared_ptr, with the risk of that pointer being invalidated (the solution being copying the smart pointer on the stack) – paercebal Feb 16 '15 at 09:50
8

It is not a matter of taste. Here are some definitive rules.

If you want to refer to a statically declared variable within the scope in which it was declared then use a C++ reference, and it will be perfectly safe. The same applies to a statically declared smart pointer. Passing parameters by reference is an example of this usage.

If you want to refer to anything from a scope that is wider than the scope in which it is declared then you should use a reference counted smart pointer for it to be perfectly safe.

You can refer to an element of a collection with a reference for syntactic convenience, but it is not safe; the element can be deleted at anytime.

To safely hold a reference to an element of a collection you must use a reference counted smart pointer.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
John Morrison
  • 81
  • 1
  • 1
7

There is problem with "use references wherever possible" rule and it arises if you want to keep reference for further use. To illustrate this with example, imagine you have following classes.

class SimCard
{
    public:
        explicit SimCard(int id):
            m_id(id)
        {
        }

        int getId() const
        {
            return m_id;
        }

    private:
        int m_id;
};

class RefPhone
{
    public:
        explicit RefPhone(const SimCard & card):
            m_card(card)
        {
        }

        int getSimId()
        {
            return m_card.getId();
        }

    private:
        const SimCard & m_card;
};

At first it may seem to be a good idea to have parameter in RefPhone(const SimCard & card) constructor passed by a reference, because it prevents passing wrong/null pointers to the constructor. It somehow encourages allocation of variables on stack and taking benefits from RAII.

PtrPhone nullPhone(0);  //this will not happen that easily
SimCard * cardPtr = new SimCard(666);  //evil pointer
delete cardPtr;  //muahaha
PtrPhone uninitPhone(cardPtr);  //this will not happen that easily

But then temporaries come to destroy your happy world.

RefPhone tempPhone(SimCard(666));   //evil temporary
//function referring to destroyed object
tempPhone.getSimId();    //this can happen

So if you blindly stick to references you trade off possibility of passing invalid pointers for the possibility of storing references to destroyed objects, which has basically same effect.

edit: Note that I sticked to the rule "Use reference wherever you can, pointers wherever you must. Avoid pointers until you can't." from the most upvoted and accepted answer (other answers also suggest so). Though it should be obvious, example is not to show that references as such are bad. They can be misused however, just like pointers and they can bring their own threats to the code.


There are following differences between pointers and references.

  1. When it comes to passing variables, pass by reference looks like pass by value, but has pointer semantics (acts like pointer).
  2. Reference can not be directly initialized to 0 (null).
  3. Reference (reference, not referenced object) can not be modified (equivalent to "* const" pointer).
  4. const reference can accept temporary parameter.
  5. Local const references prolong the lifetime of temporary objects

Taking those into account my current rules are as follows.

  • Use references for parameters that will be used locally within a function scope.
  • Use pointers when 0 (null) is acceptable parameter value or you need to store parameter for further use. If 0 (null) is acceptable I am adding "_n" suffix to parameter, use guarded pointer (like QPointer in Qt) or just document it. You can also use smart pointers. You have to be even more careful with shared pointers than with normal pointers (otherwise you can end up with by design memory leaks and responsibility mess).
Community
  • 1
  • 1
mip
  • 8,355
  • 6
  • 53
  • 72
  • 3
    The problem with your example is not that references are unsafe, but that you are relying onto something out of the scope of your object instance to keep your private members alive. `const SimCard & m_card;` is just a badly written code. – plamenko Jan 25 '16 at 20:13
  • 1
    @plamenko I'm affraid you don't understand the purpose of the example. Whether `const SimCard & m_card` is correct or not depends on context. The message in this post is not that references are unsafe (tho' they can be if one tries hard). The message is that you should not stick blindly to "use references whenever possible" mantra. Example is an outcome of agressive usage of "use references whenever possible" doctrine. This should be clear. – mip Jan 26 '16 at 07:48
  • There are two things that bother me with your answer because I think it may mislead someone trying to learn more about the matter. 1. The post is unidirectional and it's easy to get impression that references are bad. You only provided a single example of how not to use references. 2. You were not clear in your example what's wrong with it. Yes, temporary will get destroyet, but it was not that line that was wrong, it is the implementation of the class. – plamenko Jan 26 '16 at 10:47
  • You should practically never have members like `const SimCard & m_card`. If you want to be efficient with temporaries, add `explicit RefPhone(const SimCard&& card)` constructor. – plamenko Jan 26 '16 at 10:47
  • @plamenko if you can't read with some basic comprehension then you have bigger problem than just being mislead by my post. I don't know how I could be more clear. Look at the first sentence. There's a problem with "use references whenever possible" mantra! Where in my post you have found a statement that references are bad? At the end of my post you have written where to use references, so how you came with such conclusions? This isn't a direct answer to the question? – mip Jan 26 '16 at 18:15
  • @plamenko `" Yes, temporary will get destroyet, but it was not that line that was wrong, it is the implementation of the class"` You could pass anything, but temporary. You are contradicting yourself, if you justify downvoting by saying that reference should not appear normally as a class member, because that's exatly what I'm saying. Use "references whenever possible" rule is utterly wrong and `const SimCard &` member is an outcome of this rule. It doesn't matter, which line is wrong, because either can be wrong. it's not about efficiency. – mip Jan 26 '16 at 18:34
  • @plamenko it's constructor accepting const reference, which really matters, not a class member (http://coliru.stacked-crooked.com/a/aefa11254995a7ab). `"You only provided a single example of how not to use references."` There are dozens of examples on how to use references, so what my answer would add if I wrote 10000 lines of typical examples? I'm contributing to others' answers and focus on topics, which were not covered. Moreover this isn't a question on how to use references, but when to use references vs pointers. – mip Jan 27 '16 at 03:15
5

Points to keep in mind:

  1. Pointers can be NULL, references cannot be NULL.

  2. References are easier to use, const can be used for a reference when we don't want to change value and just need a reference in a function.

  3. Pointer used with a * while references used with a &.

  4. Use pointers when pointer arithmetic operation are required.

  5. You can have pointers to a void type int a=5; void *p = &a; but cannot have a reference to a void type.

Pointer Vs Reference

void fun(int *a)
{
    cout<<a<<'\n'; // address of a = 0x7fff79f83eac
    cout<<*a<<'\n'; // value at a = 5
    cout<<a+1<<'\n'; // address of a increment by 4 bytes(int) = 0x7fff79f83eb0
    cout<<*(a+1)<<'\n'; // value here is by default = 0
}
void fun(int &a)
{
    cout<<a<<'\n'; // reference of original a passed a = 5
}
int a=5;
fun(&a);
fun(a);

Verdict when to use what

Pointer: For array, linklist, tree implementations and pointer arithmetic.

Reference: In function parameters and return types.

Shaurya Uppal
  • 3,410
  • 31
  • 31
  • 1. You don't have to use pointers to pass arrays, if their size is fixed. 2. Better to pass [`span`](https://stackoverflow.com/q/45723819/1593077)'s than arrays anyway. 3. It's not always a good idea to return references. – einpoklum Aug 20 '20 at 14:06
5

Any performance difference would be so small that it wouldn't justify using the approach that's less clear.

First, one case that wasn't mentioned where references are generally superior is const references. For non-simple types, passing a const reference avoids creating a temporary and doesn't cause the confusion you're concerned about (because the value isn't modified). Here, forcing a person to pass a pointer causes the very confusion you're worried about, as seeing the address taken and passed to a function might make you think the value changed.

In any event, I basically agree with you. I don't like functions taking references to modify their value when it's not very obvious that this is what the function is doing. I too prefer to use pointers in that case.

When you need to return a value in a complex type, I tend to prefer references. For example:

bool GetFooArray(array &foo); // my preference
bool GetFooArray(array *foo); // alternative

Here, the function name makes it clear that you're getting information back in an array. So there's no confusion.

The main advantages of references are that they always contain a valid value, are cleaner than pointers, and support polymorphism without needing any extra syntax. If none of these advantages apply, there is no reason to prefer a reference over a pointer.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
5

Copied from wiki-

A consequence of this is that in many implementations, operating on a variable with automatic or static lifetime through a reference, although syntactically similar to accessing it directly, can involve hidden dereference operations that are costly. References are a syntactically controversial feature of C++ because they obscure an identifier's level of indirection; that is, unlike C code where pointers usually stand out syntactically, in a large block of C++ code it may not be immediately obvious if the object being accessed is defined as a local or global variable or whether it is a reference (implicit pointer) to some other location, especially if the code mixes references and pointers. This aspect can make poorly written C++ code harder to read and debug (see Aliasing).

I agree 100% with this, and this is why I believe that you should only use a reference when you a have very good reason for doing so.

user606723
  • 4,918
  • 2
  • 27
  • 34
  • I also agree to a large extent, however I'm coming round to the view that the loss of built-in protection against NULL pointers is a bit too costly for purely syntactic concerns, especially as - although more explicit - pointer syntax is pretty ugly anyway. – connec Aug 14 '11 at 22:24
  • I suppose the circumstance would be an important factor as well. I think trying to use references when the current code base predominantly uses pointers would be a bad idea. If you expect their to be references then the fact that their so implicit is less important maybe.. – user606723 Aug 14 '11 at 22:28
2

The following are some guidelines.

A function uses passed data without modifying it:

  1. If the data object is small, such as a built-in data type or a small structure, pass it by value.

  2. If the data object is an array, use a pointer because that’s your only choice. Make the pointer a pointer to const.

  3. If the data object is a good-sized structure, use a const pointer or a const reference to increase program efficiency.You save the time and space needed to copy a structure or a class design. Make the pointer or reference const.

  4. If the data object is a class object, use a const reference.The semantics of class design often require using a reference, which is the main reason C++ added this feature.Thus, the standard way to pass class object arguments is by reference.

A function modifies data in the calling function:

1.If the data object is a built-in data type, use a pointer. If you spot code like fixit(&x), where x is an int, it’s pretty clear that this function intends to modify x.

2.If the data object is an array, use your only choice: a pointer.

3.If the data object is a structure, use a reference or a pointer.

4.If the data object is a class object, use a reference.

Of course, these are just guidelines, and there might be reasons for making different choices. For example, cin uses references for basic types so that you can use cin >> n instead of cin >> &n.

Community
  • 1
  • 1
Sachin Godara
  • 502
  • 4
  • 11
1

Your properly written example should look like

void add_one(int& n) { n += 1; }
void add_one(int* const n)
{
  if (n)
    *n += 1;
}

That's why references are preferable if possible ...

Slavenskij
  • 611
  • 6
  • 13
0

References are cleaner and easier to use, and they do a better job of hiding information. References cannot be reassigned, however. If you need to point first to one object and then to another, you must use a pointer. References cannot be null, so if any chance exists that the object in question might be null, you must not use a reference. You must use a pointer. If you want to handle object manipulation on your own i.e if you want to allocate memory space for an object on the Heap rather on the Stack you must use Pointer

int *pInt = new int; // allocates *pInt on the Heap
Shashikant Mitkari
  • 307
  • 1
  • 2
  • 12
0

In my practice I personally settled down with one simple rule - Use references for primitives and values that are copyable/movable and pointers for objects with long life cycle.

For Node example I would definitely use

AddChild(Node* pNode);
rokstar
  • 404
  • 1
  • 3
  • 12
-1

Just putting my dime in. I just performed a test. A sneeky one at that. I just let g++ create the assembly files of the same mini-program using pointers compared to using references. When looking at the output they are exactly the same. Other than the symbolnaming. So looking at performance (in a simple example) there is no issue.

Now on the topic of pointers vs references. IMHO I think clearity stands above all. As soon as I read implicit behaviour my toes start to curl. I agree that it is nice implicit behaviour that a reference cannot be NULL.

Dereferencing a NULL pointer is not the problem. it will crash your application and will be easy to debug. A bigger problem is uninitialized pointers containing invalid values. This will most likely result in memory corruption causing undefined behaviour without a clear origin.

This is where I think references are much safer than pointers. And I agree with a previous statement, that the interface (which should be clearly documented, see design by contract, Bertrand Meyer) defines the result of the parameters to a function. Now taking this all into consideration my preferences go to using references wherever/whenever possible.

-2

For pointers, you need them to point to something, so pointers cost memory space.

For example a function that takes an integer pointer will not take the integer variable. So you will need to create a pointer for that first to pass on to the function.

As for a reference, it will not cost memory. You have an integer variable, and you can pass it as a reference variable. That's it. You don't need to create a reference variable specially for it.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rabbiya Shahid
  • 422
  • 3
  • 14
  • 4
    Nope. A function that takes a pointer does not require allocation of a pointer variable: you can pass a temporary `&address`. A reference certainly will cost memory if it is a member of an object, and plus, all extant compilers actually implement references as addresses, so you save nothing in terms of parameter-passing or dereferencing either. – underscore_d Feb 26 '16 at 03:08