3862

What is the difference between a pointer variable and a reference variable?

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
prakash
  • 58,901
  • 25
  • 93
  • 115
  • 1
    A local reference (i.e., one not in a struct or class) does not necessarily allocate storage. You can tell because of the sizeof difference between sizeof(int &) and sizeof(struct { int &x; }). – MSN Oct 08 '10 at 16:56
  • 133
    I think point 2 should be "A pointer is allowed to be NULL but a reference is not. Only malformed code can create a NULL reference and its behavior is undefined." – Mark Ransom Oct 08 '10 at 17:21
  • 30
    Pointers are just another type of object, and like any object in C++, they can be a variable. References on the other hand are never objects, *only* variables. – Kerrek SB Jun 16 '12 at 10:14
  • 29
    This compiles without warnings: `int &x = *(int*)0;` on gcc. Reference can indeed point to NULL. – Calmarius Aug 13 '12 at 09:00
  • 7
    I'm not sure I agree that "references are syntactic sugar". How would you design copy constructors in your language if you didn't have references? – Kerrek SB Sep 06 '12 at 08:20
  • 1
    Probably we could take the address of a reference, like the idiom adopted in implementing the assignment operator, i.e. `T& T::operator=(const T& rhs) { if (this == &rhs) return *this; ... }`. – Qiang Xu Oct 26 '12 at 16:40
  • 2
    also helpful [link](http://www.embedded.com/electronics-blogs/programming-pointers/4023307/References-vs-Pointers) – 4pie0 Feb 21 '13 at 15:47
  • 9
    I don't feel qualified to edit the "clarify a misconception" part of this question, but I think it should be observed that if `int i` lives in a register for its entire life, the reference isn't likely to be a pointer - it can simply alias the same register. – Drew Dormann Apr 24 '13 at 18:53
  • 28
    reference is a variable alias – Khaled.K Dec 23 '13 at 08:53
  • 4
    References are not just syntactic sugar: they are ALWAYS in a defined state. This is enforced by the compiler. Pointers have no such guarantee. – EvertW Apr 22 '14 at 14:57
  • 26
    I like how the very first sentence is a total fallacy. References have their own semantics. – Lightness Races in Orbit Jun 01 '14 at 01:58
  • 9
    @Calmarius No, that is not correct. That's a reference to whatever's at that memory location. The reference itself is valid. Accessing what's there though - is undefined. – iheanyi Jul 21 '14 at 20:01
  • 16
    @Calmarius of course, to even get there, you dereferenced a null pointer. . .which is itself undefined. . . – iheanyi Jul 21 '14 at 20:09
  • 1
    This questions shows pointer arithmetic being done on a reference ("`&obj + 5`"). Doesn't this break aliasing assumptions, where the call site assumes that a called function will not do such arithmetic. Thereby, meaning reference arithmetic is UB? – Aaron McDaid Jul 29 '15 at 16:48
  • 1
    Pointer basically stores the address of its pointee. – Moiz Sajid Aug 30 '15 at 11:37
  • 5
    int *p = NULL; int &r=*p; reference pointing to NULL; if(r){} -> boOm ;) – uss Oct 04 '15 at 12:34
  • 1
    @QiangXu No, that takes the address of the reference's target. Read it again: A reference is an alias to another object. (Aside from at the creation stage,) its semantics are entirely identical to if you used the target's original name. – underscore_d Oct 11 '15 at 17:24
  • 1
    I wouldn't say that references are implemented as pointers in C++, they are two different abstractions for *address* of an object. Think how the hardware works: in hardware you don't have "pointers", you have registers, memory and instructions that operate on the registers and memory. – t0rakka Nov 16 '16 at 00:11
  • 2
    I like to imaging that variables are people at a party, then a _pointer_ is someone who goes around with their finger normally aimed at someone else and who that is can be changed and in some cases either the someone else leaves the party and can no longer be pointed at (out-of-scope) or murdered (destroyed, it is a _bad_ party!), on other occasions the pointer person can be made to point to a new person (value modified) or the floor (set to 0, `nullptr` etc.). In comparison, a _reference_ variable is a new name-badge that a person can put on themselves (to which a pointer can use as well!) – SlySven Dec 23 '17 at 05:21
  • 2
    `a pointer and a reference both occupy the same amount of memory` - this is wrong. Pointer to a virtual function may occupy more memory than a reference. – Dmitry Sazonov Apr 19 '18 at 12:11
  • 4
    Am I the only one who thinks that pointers are easier to read and they clarify the code more than references? – Beyondo Jun 09 '18 at 10:17
  • 1
    A very important point: the programmer has to manage the memory of pointers, but not of references. – Apollys supports Monica Oct 01 '18 at 20:55
  • 1
    A pointer can be null, i.e. assume a value that clearly doesn't point to any valid object or function. On the other hand, 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 or function obtained by dereferencing a null pointer, which causes undefined behavior. – HelloGoodbye Oct 23 '18 at 08:05
  • 2
    Are none of the answers a solution to your question? If not, I am very curious to know why. – GoWiser Sep 25 '21 at 03:35
  • A "reference variable" is syntactic sugar over a "pointer variable". i.e. same but different. Different but the same. We can argue, and we can nitpick, there's `*` and then there's `&`, and so forth, plenty of devil in the finer details but, at the end of the day, does it really matter? You start coding with one, and when you're ready, you transition to the other. – Stephen Quan Dec 06 '22 at 00:49
  • @StephenQuan several years came by and this fallacy is kept copying. It is not syntax sugar for a pointer, because rules governing it quite different. Also reference isn't an objecy. If it was sugar for pointer, it would be. – Swift - Friday Pie Aug 09 '23 at 21:04

44 Answers44

2178
  1. A pointer can be re-assigned:

    int x = 5;
    int y = 6;
    int *p;
    p = &x;
    p = &y;
    *p = 10;
    assert(x == 5);
    assert(y == 10);
    

    A reference cannot be re-bound, and must be bound at initialization:

    int x = 5;
    int y = 6;
    int &q; // error
    int &r = x;
    
  2. A pointer variable has its own identity: a distinct, visible memory address that can be taken with the unary & operator and a certain amount of space that can be measured with the sizeof operator. Using those operators on a reference returns a value corresponding to whatever the reference is bound to; the reference’s own address and size are invisible. Since the reference assumes the identity of the original variable in this way, it is convenient to think of a reference as another name for the same variable.

    int x = 0;
    int &r = x;
    int *p = &x;
    int *p2 = &r;
    
    assert(p == p2); // &x == &r
    assert(&p != &p2);
    
  3. You can have arbitrarily nested pointers to pointers offering extra levels of indirection. References only offer one level of indirection because references to references collapse.

    int x = 0;
    int y = 0;
    int *p = &x;
    int *q = &y;
    int **pp = &p;
    
    **pp = 2;
    pp = &q; // *pp is now q
    **pp = 4;
    
    assert(y == 4);
    assert(x == 2);
    
  4. A pointer can be assigned nullptr, whereas a reference must be bound to an existing object. If you try hard enough, you can bind a reference to nullptr, but this is undefined and will not behave consistently.

    /* the code below is undefined; your compiler may optimise it
     * differently, emit warnings, or outright refuse to compile it */
    
    int &r = *static_cast<int *>(nullptr);
    
    // prints "null" under GCC 10
    std::cout
        << (&r != nullptr
            ? "not null" : "null")
        << std::endl;
    
    bool f(int &r) { return &r != nullptr; }
    
    // prints "not null" under GCC 10
    std::cout
        << (f(*static_cast<int *>(nullptr))
            ? "not null" : "null")
        << std::endl;
    

    You can, however, have a reference to a pointer whose value is nullptr.

  5. Pointers can iterate over an array; you can use ++ to go to the next item that a pointer is pointing to, and + 4 to go to the 5th element. This is no matter what size the object is that the pointer points to.

  6. A pointer needs to be dereferenced with * to access the memory location it points to, whereas a reference can be used directly. A pointer to a class/struct uses -> to access its members whereas a reference uses a ..

  7. References cannot be put into an array, whereas pointers can be (Mentioned by user @litb)

  8. Const references and rvalue references can be bound to temporaries (see temporary materialization). Pointers cannot (not without some indirection):

    const int &x = int(12); // legal C++
    int *y = &int(12); // illegal to take the address of a temporary.
    

    This makes const & more convenient to use in argument lists and so forth.

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
Brian R. Bondy
  • 339,232
  • 124
  • 596
  • 636
  • 3
    Reference can be null. In some cases, you pass refrence params in as this: function(*ptr); If ptr is NULL, so will be the reference. –  Sep 11 '08 at 21:01
  • 34
    ...but dereferencing NULL is undefined. For example, you can't test if a reference is NULL (e.g., &ref == NULL). – Pat Notz Sep 11 '08 at 22:07
  • 1
    IN VC++ *ptr will crash, pretty sure in gc++ it will segfault too – Brian R. Bondy Sep 11 '08 at 23:37
  • 1
    I think point 2 is incorrect. See this example program: http://pastebin.com/f5252f8a8 This implies that on gcc on my machine, the reference is implemented with a pointer. Output: Size of class: 8 Value of ref before hack: 1 Value of ref after hack: 2 Value of ref after hack, with y changed: 3 – Nick Sep 12 '08 at 14:21
  • 96
    Number 2 is *not* true. A references is not simply "another name for the same variable." References may be passed to functions, stored in classes, etc. in a manner very similar to pointers. They exist independently from the variables they point to. – Derek Park Sep 12 '08 at 23:37
  • 5
    Also this: "A pointer has its own memory address and size on the stack". Pointers need not be allocated on the stack (and most of them are generally not.) – Derek Park Sep 12 '08 at 23:38
  • 5
    Derek a pointer is a variable just like any other one. On an x86 system it is 4 bytes. These 4 bytes are on the stack. I didn't claim what they point to are on the stack. – Brian R. Bondy Sep 13 '08 at 20:11
  • 4
    I don't think it is good and safe to think that, because it's wrong :-p I'd be inclined to remove point 2 from an otherwise good answer. – Nick Sep 14 '08 at 21:45
  • 1
    Brian, referring to point 2, do you know of any compiler that actually does this? It is implementation-dependent, but references are typically implemented with pointers. – Derek Park Sep 18 '08 at 21:20
  • 15
    how the internal structure of a reference is implemented doesn't matter. What matters is that the address of the reference is the same as the address of the variable itself. Therefore they can be used interchangeably. – Brian R. Bondy Sep 19 '08 at 02:14
  • 2
    Nick you could use the same argument as your link to say that pointers are implemented as pointers to pointers but you didn't mention it. int x = 0; int y = 0; int *p = &x; *(int**)(&p) = &y; Because it doesn't matter. – Brian R. Bondy Sep 19 '08 at 02:24
  • 2
    I verified by the way that a reference does take up some space on the stack, I modified my #3 to include this info. The address of operator though still does specify the same as the variable that it refers to. – Brian R. Bondy Sep 19 '08 at 03:24
  • 37
    Brian, the stack is not relevant. References and pointers do not have to take space on the stack. They can both be allocated on the heap. – Derek Park Sep 19 '08 at 04:33
  • 1
    Derek please see my previous post, I don't think you read it or you didn't read it carefully enough... "Derek a pointer is a variable just like any other one. On an x86 system it is 4 bytes. These 4 bytes are on the stack. I didn't claim what they point to are on the stack" – Brian R. Bondy Sep 19 '08 at 11:50
  • 25
    Brian, the fact that a variable (in this case a pointer or reference) requires space does *not* mean it requires space on the stack. Pointers and references may not only *point* to the heap, they may actually be *allocated* on the heap. – Derek Park Sep 19 '08 at 15:26
  • 5
    agree, but i'm just trying to get the point across that in this situation: int x = 0; int *p = &x;, the p takes up 4 bytes on the stack. I know it is possible to say (new int*) to allocate the pointer itself on the heap. – Brian R. Bondy Sep 19 '08 at 17:55
  • 1
    you an modify if you'd like to be more explicit there, but I think its not really needed. – Brian R. Bondy Sep 19 '08 at 17:55
  • 47
    another important diff: references cannot be stuffed into an array – Johannes Schaub - litb Feb 27 '09 at 21:10
  • 15
    Derek, there is no mention in the standard that a reference requires space. regardless what you do with a reference, even if you take its address, there can be no additional space involved and a reference can just be a "real" alias for the other object it references. – Johannes Schaub - litb Feb 27 '09 at 21:13
  • 7
    @litb: While the standard might not require space allocated for the reference, in many cases the compiler will be forced to reserve space. Consider a reference within a class, surely each instance of the class can refer to different external objects, and to which object they refer must be held somehow --in most implementations as an automatically dereferenced pointer (I cannot really think of any other possible implementation that fits all use cases, but then again, I am no expert) – David Rodríguez - dribeas Jan 14 '10 at 17:01
  • 2
    I found that looking at the images on this page: http://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Companion/cxx_crib/pointers.html while reading this post made it super easy to understand the difference ;) – polyclick Jul 25 '12 at 19:27
  • 5
    @Brian: References can take up memory, just as pointers do. For example, if you have a member variable of a class which is a reference, then every instance of the class will have memory allocated for that reference. In some cases, a compiler can optimize away the need to allocate memory for a reference; and there's no nice way to get the address of a reference in your code (&my_reference just returns the address of the referred-to object). In those aspects I agree that references act as if they don't take up memory - but they can. – Tyler Sep 12 '08 at 12:00
  • 1
    isn't what `7)` adds to `2)` is *only* that references can be implemented differently in different language-implementations? – n611x007 May 07 '13 at 14:40
  • 3
    @David Rodríguez - dribeas: I believe you are thinking backward in your previous comment. Indeed the compiler can be forced to reserve space for a reference, but there are many cases when it won't need to and such cases are often easy to detect at compile time. When that occurs the compiler won't use any space for the reference. It's much harder for compilers to optimize away pointers: they first have to ensure no code ever takes the address of the pointer or could derive it from the context. – kriss Mar 14 '14 at 10:15
  • 1
    Bullet 1 is somewhat incorrect. It says that references must be initialized (correct) and that they cannot be re-assigned (incorrect): http://ideone.com/hkwoRZ – Johann Gerell Aug 20 '14 at 08:06
  • 1
    @kriss: Since introduction of lambdas, which can capture references by reference, the opportunity to optimize away the storage actually holding the address of the referent and the associated analysis to determine whether doing so is safe, is the same for pointers and references. – Ben Voigt Sep 01 '14 at 17:43
  • 7
    @JohannGerell: You are incorrect. Your example doesn't reassign the reference. The left operand of the assignment resolves to the object `a`, not the reference `c`. – Ben Voigt Sep 01 '14 at 17:45
  • 2
    @BenVoigt: You are correct! http://ideone.com/SwRZ6r - thanks for teaching me something today, I might very well have caused one or two bugs in my days due to that misunderstanding... – Johann Gerell Sep 02 '14 at 01:49
  • 2
    @Ben Voigt: I'm not sure I understand you comment. What does introduction of lambda change for code not using lambda ? Also when optimizing away pointers (which can be indeed done in some cases) you have to ensure it's not a void pointer. If you look at clang assembly output, there are cases where it introduces such checks before optimizing away a pointer in subsequent code. – kriss Sep 02 '14 at 07:57
  • 1
    @kriss: You said "for compilers to optimize away pointers: they first have to ensure no code ever takes the address of the pointer". Capture-by-reference lambdas, when a reference appears in the closure set, actually store the address of the reference's internal storage, so now the compiler optimizing references is faced with the exact same problems it has always had with pointers. – Ben Voigt Sep 02 '14 at 14:01
  • 2
    @BenVoigt: I still does not understand why it should matter especially with introduction of lambdas, storing the reference external storage is perfectly OK, because that's the meaning of the reference (a reference is a mere alias to some existing storage). Optimizing reference away is much more simple than that, it's merely treating it as an alias of the original variable. That's something hard through function interfaces but easy inside functions body or inlining (because references will always be aliasing the same storage, which is false for pointers). – kriss Sep 02 '14 at 14:45
  • 1
    @kriss: Guess you haven't understood my point. A lambda capture may need to take the address of the reference itself, NOT the object the reference is bound to. There's no other language feature which creates a reference-to-reference. – Ben Voigt Sep 02 '14 at 15:29
  • 2
    @BenVoigt: I believe I will have to dig in that, because "taking the address of the reference itself" is still a meaningless sentence to me (because the reference having an address or not should be an implementation detail). I understand C++ lambda as equivalent to a function call with a closure context (all you can do with lambdas can be done using functor objects). There are already troubles (hidden pointers) for optimizers as soon as you pass a parameter to a function or class by reference and I expect the same kind of troubles with lambdas. But I can't see why there would be more troubles. – kriss Sep 02 '14 at 16:19
  • 2
    A pointer can be made not-reassignable: int x; int *const p = &x; Note that const after the asterisk character, it is not the same as if it were before the asterisk. Now you cannot write anything like p=null or other re-assigning but you can still write *p = 5. A const pointer to const data would be const int *const p = &x; or int const *const p = &x; (these two are equivalent). – Marian Spanik Apr 09 '15 at 14:14
  • 2
    Int'restin'ly, point 9 is one of the areas where C++ differs from C - in C you *can* take the address of a temporary: `int *y = &(int){12};`. – Alex Celeste Apr 20 '15 at 20:32
  • 1
    re: 2. pointer variable get 4 bytes (on some machine) on the stack, and reference variable too. This part of Your sentence is wrong. – Jacek Cz Mar 31 '16 at 11:23
  • 3
    @Leushenko in that C code `(int){12}` is a compound literal, not a temporary – M.M Feb 23 '17 at 05:07
  • 2
    Re 4. : it's a compiling error just because you have not dereferenced it. It is not protection from nullptr, it's just because there is no special null-reference which cannot be used as initialiser without type cast while there is nullptr which can be used without type cast. It's easy to write nullreference_t which will do the same. – Euri Pinhollow Apr 13 '17 at 11:57
  • 2
    Pointers work as last parameter before an elipsis / varargs function (`int printf( char const * format, ... )`). **References do not**, with rather surprising results if you try... – DevSolar Feb 12 '18 at 16:00
  • Nice answer. Also, guess I am the 1500th upvoter :) – Jarvis Mar 18 '19 at 06:48
  • 1
    A pointer cannot be reassigned if it is `const` qualified. The non-reassignment benefit of a reference is available that way in pointers. – Kaz Oct 24 '19 at 22:35
  • So basically, references are constant pointers that represent the variable/object as `*ptr` would? – theX Sep 08 '20 at 00:21
  • Regarding number 7, references CAN be stored in standard containers if you use [`std::reference_wrapper`](https://en.cppreference.com/w/cpp/utility/functional/reference_wrapper). – Olivia Stork Nov 12 '20 at 01:56
  • Regarding the ancient reference-by-reference capture debate: that’s just an implementation detail. The compiler doesn’t *have* to do that, it can simply copy the reference as it is immutable and no identity, no matter how it is used. That doesn’t work for a const pointer as it does have identity which can be revealed by taking address of that pointer itself. – numzero Sep 05 '21 at 23:15
  • Only pointers can link to objects on the heap (new). References link to objects on the stack. – Kur Ich Nov 07 '21 at 14:23
  • @KurIch: There is no such restriction, a reference can be bound to an object with any storage duration. – Ben Voigt Oct 10 '22 at 22:03
525

What's a C++ reference (for C programmers)

A reference can be thought of as a constant pointer (not to be confused with a pointer to a constant value!) with automatic indirection, ie the compiler will apply the * operator for you.

All references must be initialized with a non-null value or compilation will fail. It's neither possible to get the address of a reference - the address operator will return the address of the referenced value instead - nor is it possible to do arithmetics on references.

C programmers might dislike C++ references as it will no longer be obvious when indirection happens or if an argument gets passed by value or by pointer without looking at function signatures.

C++ programmers might dislike using pointers as they are considered unsafe - although references aren't really any safer than constant pointers except in the most trivial cases - lack the convenience of automatic indirection and carry a different semantic connotation.

Consider the following statement from the C++ FAQ:

Even though a reference is often implemented using an address in the underlying assembly language, please do not think of a reference as a funny looking pointer to an object. A reference is the object. It is not a pointer to the object, nor a copy of the object. It is the object.

But if a reference really were the object, how could there be dangling references? In unmanaged languages, it's impossible for references to be any 'safer' than pointers - there generally just isn't a way to reliably alias values across scope boundaries!

Why I consider C++ references useful

Coming from a C background, C++ references may look like a somewhat silly concept, but one should still use them instead of pointers where possible: Automatic indirection is convenient, and references become especially useful when dealing with RAII - but not because of any perceived safety advantage, but rather because they make writing idiomatic code less awkward.

RAII is one of the central concepts of C++, but it interacts non-trivially with copying semantics. Passing objects by reference avoids these issues as no copying is involved. If references were not present in the language, you'd have to use pointers instead, which are more cumbersome to use, thus violating the language design principle that the best-practice solution should be easier than the alternatives.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Christoph
  • 164,997
  • 36
  • 182
  • 240
  • 1
    @Christoph: well references can be dangling only if you got it somewhere through dereferencing some pointer. – kriss Jan 29 '10 at 15:05
  • 22
    @kriss: No, you can also get a dangling reference by returning an automatic variable by reference. – Ben Voigt Nov 02 '10 at 06:14
  • 2
    @Ben Voight: OK, but that's really calling for troubles. Some compilers even return warnings if you do that. – kriss Nov 02 '10 at 07:38
  • 20
    @kriss: It's virtually impossible for a compiler to detect in the general case. Consider a member function that returns a reference to a class member variable: that's safe and should not be forbidden by the compiler. Then a caller that has an automatic instance of that class, calls that member function, and returns the reference. Presto: dangling reference. And yes, it's going to cause trouble, @kriss: that's my point. Many people claim that an advantage of references over pointers is that references are always valid, but it just isn't so. – Ben Voigt Nov 02 '10 at 13:15
  • 1
    @Ben Voigt: are you sure this scenario will work with non const references ? Isn't it what Matt Price is speaking about in it's answer ? But I agree, returned references can be dangling, even non auto objects can be explicitely deleted. – kriss Nov 02 '10 at 13:56
  • 7
    @kriss: No, a reference into an object of automatic storage duration is very different from a temporary object. Anyway, I was just providing a counter-example to your statement that you can only get an invalid reference by dereferencing an invalid pointer. Christoph is correct -- references are not any safer than pointers, a program which uses references exclusively can still break type safety. – Ben Voigt Nov 02 '10 at 15:15
  • 11
    References are not a kind of pointer. They are a new name for an existing object. – catphive Jul 20 '11 at 01:28
  • 29
    @catphive: true if you go by language semantics, not true if you actually look at the implementation; C++ is a far more 'magical' language that C, and if you remove the magic from references, you end up with a pointer – Christoph Jul 23 '11 at 09:07
  • 5
    Yes the C++ FAQ is wrong. A reference is an own entity, which merely refers to an object or function. Even by "language semantics". But you cannot depict between a reference and its target in most situations. – Johannes Schaub - litb Jul 23 '11 at 09:28
  • 5
    Another example of a reference being invalidated is a reference to an element of an std container such as a vector. When you push elements into it, it can reallocate its storage and invalidate your references. This is generally true whenever something has a reference to something it doesn't own. Its owner may do unexpected stuff to it without you knowing, and this will give you a dangling reference. – saolof May 06 '17 at 16:35
  • 1
    *"All references must be initialized with a non-null value or compilation will fail."* - That's probably an attempt to simplify things, but it went terribly wrong: `const int& ri = int(0);`. Perfectly valid code, that compiles, and initializes a reference with an object that has a value of null. Apart from that, you cannot initialize a reference with a value anyway. A reference simply has no value. That should probably be reworded. – IInspectable Oct 29 '17 at 00:31
  • 4
    @IInspectable `const int &ri = (int)0;` is correct code. `ri` is initialized to refer to a temporary int whose lifetime is extended. This is exactly a case of initializing a reference with a value which you later claim is not possible. It is also incorrect to say that a reference has no value. Its value is the value of the object referred to. – M.M Nov 06 '17 at 05:21
  • 2
    @Christoph *"All references must be initialized with a non-null value or compilation will fail."* is a false statement.Compilation will fail if no initializer is provided; however it is possible to write for example `const int& r = *(int *)nullptr;` . This is undefined behaviour with no diagnostic required; in fact the compiler cannot reject it unless it can be proven that all execution paths reach that line. – M.M Nov 06 '17 at 05:23
  • 1
    @M.M: What specifically is more correct about your use of a C-style cast? And no, a reference has no value. It is an alias. It's not something that exists in memory or otherwise. As such, it has no value. It can just be used *as if* it did, writing through to the object the reference is bound to. – IInspectable Nov 06 '17 at 12:48
  • 3
    @IInspectable `*(int *)nullptr` dereferences a null pointer, `int(0)` or `(int)0` is exactly the same as `0`, i.e. an integer with value zero. – M.M Nov 06 '17 at 20:02
  • 2
    Good answer, BUT: when you said about C++ "_thus violating the language design principle that the best-practice solution should be easier than the alternatives._", I actually laughed! This is soooo ironic. The C++ way is frequently 10x more complicated and syntactically ridiculous than the C way. The amount of hoops people will jump through in C++ to obtain a grain-of-sand-sized portion more of "type safety" while dumping in buckets and buckets of syntax still astonishes me. That being said, I truly love the C++ _compiler_, and would choose to use it any day over the C compiler. – Gabriel Staples Oct 22 '20 at 22:42
  • 2
    Don't get me wrong: I do believe in simplicity, and I use const references all the time (but not non-const references as I think they cause confusion and are bad practice). I just find that nearly all C++ code I read does not choose simplicity, regardless of what it claims. It chooses as much complexity as is humanly possible. Gobs of syntax for a little _perceived_ safety. I'd argue that human-readable code is safer than code which makes you jump through hoops and bend over backwards twice before it becomes the right type to pass in somewhere. [end of rant]. – Gabriel Staples Oct 22 '20 at 23:40
226

If you want to be really pedantic, there is one thing you can do with a reference that you can't do with a pointer: extend the lifetime of a temporary object. In C++ if you bind a const reference to a temporary object, the lifetime of that object becomes the lifetime of the reference.

std::string s1 = "123";
std::string s2 = "456";

std::string s3_copy = s1 + s2;
const std::string& s3_reference = s1 + s2;

In this example s3_copy copies the temporary object that is a result of the concatenation. Whereas s3_reference in essence becomes the temporary object. It's really a reference to a temporary object that now has the same lifetime as the reference.

If you try this without the const it should fail to compile. You cannot bind a non-const reference to a temporary object, nor can you take its address for that matter.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Matt Price
  • 43,887
  • 9
  • 38
  • 44
  • 7
    but whats the use case for this ? – Ahmad Mushtaq Oct 22 '09 at 14:10
  • 25
    Well, s3_copy will create a temporary and then copy construct it into s3_copy whereas s3_reference directly uses the temporary. Then to be really pedantic you need to look at the Return Value Optimization whereby the compiler is allowed to elide the copy construction in the first case. – Matt Price Oct 22 '09 at 18:14
  • 7
    @digitalSurgeon: The magic there is quite powerful. The object lifetime is extended by the fact of the `const &` binding, and only when the reference goes out of scope the destructor of the _actual_ referenced type (as compared to the reference type, that could be a base) is called. Since it is a reference, no slicing will take place in between. – David Rodríguez - dribeas Jan 14 '10 at 17:06
  • 11
    Update for C++11: last sentence should read "You cannot bind a non-const lvalue reference to a temporary" because you _can_ bind a non-const _rvalue_ reference to a temporary, and it has the same lifetime-extending behaviour. – Oktalist Nov 10 '13 at 20:14
  • 1
    Can someone give me a concrete example of how a const& can extend the life of the variable it's referencing? Since references must be initialized, they'll always have to be declared after the variable it'll be referencing, and so I can't think of a situation where the reference would be on a different scope, or on a scope that would last longer than the variable's scope. – Bruno Santos Mar 15 '14 at 01:32
  • 1
    @BrunoSantos First of all, references are not "initialized", you are confusing how they work with pointers. To the question: Think of operators overloading. When for example a sum of 2 variables happens, the machine allocates a temporary memory so it doesn't change the data from within the variables themselves, moves first in and then sums the second to the value in the temporary memory. – Lilian A. Moraru Jul 22 '14 at 00:28
  • 2
    @BrunoSantos You missed the point. A `const &` can prolong the lifetime of a **temporary**, not a variable. Normally a temporary's lifetime is merely the full-expression in which it is generated, unless it's `const`-referenced, in which case, it gets the lifetime of the reference variable. (Copying/moving it into a named variable aren't technically lifetime extension.) – underscore_d Apr 15 '16 at 13:41
  • 9
    @AhmadMushtaq: The key use of this is **derived classes**. If there is no inheritance involved, you might as well use value semantics, which will be cheap or free due to RVO/move construction. But if you have `Animal x = fast ? getHare() : getTortoise()` then `x` will face the classic slicing problem, while `Animal& x = ...` will work correctly. – Arthur Tacca Nov 02 '17 at 11:04
  • Here is your "use case": `void foo(const std::string&); foo(s1 + s2);` – Danvil Nov 01 '20 at 00:38
177

Apart from syntactic sugar, a reference is a const pointer (not pointer to a const). You must establish what it refers to when you declare the reference variable, and you cannot change it later.

Update: now that I think about it some more, there is an important difference.

A const pointer's target can be replaced by taking its address and using a const cast.

A reference's target cannot be replaced in any way short of UB.

This should permit the compiler to do more optimization on a reference.

  • 16
    I think this is the best answer by far. Others talk about references and pointers like they are different beasts and then lay out how they differ in behavior. It doesn't make things any easier imho. I've always understood references as being a `T* const` with different syntactic sugar (that happens to eliminate a lot of * and & from your code). – Carlo Wood Jan 10 '17 at 01:34
  • 10
    "A const pointer's target can be replaced by taking its address and using a const cast." Doing so is undefined behavior. See https://stackoverflow.com/questions/25209838/is-this-undefined-behavior-with-const-cast for details. – dgnuff Jun 22 '18 at 04:51
  • 2
    Trying to change either the referent of a reference or the value of a const pointer (or any const scalar) is equality illegal. What you can do: remove a const qualification that was added by implicit conversion: `int i; int const *pci = &i; /* implicit conv to const int* */ int *pi = const_cast(pci);` is OK. – curiousguy Jun 29 '18 at 16:00
  • 3
    The difference here is UB versus literally impossible. There is no syntax in C++ that would let you change what reference points at. –  Jun 29 '18 at 16:03
  • 1
    Not impossible, harder, you can just access the memory area of the pointer that is modeling that reference and change its content. That can certainly be done. – Nicolas Bousquet Nov 17 '18 at 21:39
  • @CarloWood exactly, Godbolt shows 0 difference in the asm output of using a pointer vs using a reference. It's still a const pointer on the stack. The only difference it has is at the compiler level, i.e. the compiler interprets 'b' instead of '*b' as getting the value being pointed to and '&b' instead of b and the address of the actual const pointer can't be taken – Lewis Kelsey Apr 11 '20 at 17:04
  • This is just.... _totally wrong_. A reference is *not* a glorified pointer, no matter what similarities the two may have under the hood. In the problem space, they are two different things. C++ is not B. – Spencer May 10 '22 at 20:26
  • FWIW, it is no longer true that a reference cannot be retargeted. Placement-new of a new object having a reference member (right over the top of the old reference member) is no longer UB. – Ben Voigt Oct 10 '22 at 22:07
139

Contrary to popular opinion, it is possible to have a reference that is NULL.

int * p = NULL;
int & r = *p;
r = 1;  // crash! (if you're lucky)

Granted, it is much harder to do with a reference - but if you manage it, you'll tear your hair out trying to find it. References are not inherently safe in C++!

Technically this is an invalid reference, not a null reference. C++ doesn't support null references as a concept as you might find in other languages. There are other kinds of invalid references as well. Any invalid reference raises the spectre of undefined behavior, just as using an invalid pointer would.

The actual error is in the dereferencing of the NULL pointer, prior to the assignment to a reference. But I'm not aware of any compilers that will generate any errors on that condition - the error propagates to a point further along in the code. That's what makes this problem so insidious. Most of the time, if you dereference a NULL pointer, you crash right at that spot and it doesn't take much debugging to figure it out.

My example above is short and contrived. Here's a more real-world example.

class MyClass
{
    ...
    virtual void DoSomething(int,int,int,int,int);
};

void Foo(const MyClass & bar)
{
    ...
    bar.DoSomething(i1,i2,i3,i4,i5);  // crash occurs here due to memory access violation - obvious why?
}

MyClass * GetInstance()
{
    if (somecondition)
        return NULL;
    ...
}

MyClass * p = GetInstance();
Foo(*p);

I want to reiterate that the only way to get a null reference is through malformed code, and once you have it you're getting undefined behavior. It never makes sense to check for a null reference; for example you can try if(&bar==NULL)... but the compiler might optimize the statement out of existence! A valid reference can never be NULL so from the compiler's view the comparison is always false, and it is free to eliminate the if clause as dead code - this is the essence of undefined behavior.

The proper way to stay out of trouble is to avoid dereferencing a NULL pointer to create a reference. Here's an automated way to accomplish this.

template<typename T>
T& deref(T* p)
{
    if (p == NULL)
        throw std::invalid_argument(std::string("NULL reference"));
    return *p;
}

MyClass * p = GetInstance();
Foo(deref(p));

For an older look at this problem from someone with better writing skills, see Null References from Jim Hyslop and Herb Sutter.

For another example of the dangers of dereferencing a null pointer see Exposing undefined behavior when trying to port code to another platform by Raymond Chen.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • 4
    As a nitpick, I'd say that the reference isn't actually null - it references bad memory. Although it is a valid point that just because it's a reference, doesn't mean that it refers to something that's valid – Nick Sep 12 '08 at 13:42
  • 71
    The code in question contains undefined behavior. Technically, you cannot do anything with a null pointer except set it, and compare it. Once your program invokes undefined behavior, it can do anything, including appearing to work correctly until you are giving a demo to the big boss. – KeithB Sep 12 '08 at 16:00
  • 1
    I didn't test it but I think the code above just crash at the second line while dereferencing the NULL pointer. – Vincent Robert Sep 19 '08 at 12:00
  • 2
    @Vincent: In fact, no, sometimes, the second line is silently invoked (remember compilers can implement references as pointers, so...)... So the crash happens when you us the reference. – paercebal Oct 10 '08 at 20:39
  • 1
    Anyway, the coder dereferenced a pointer without testing it. This is the source of the error. At that point, or sometimes after, the program will crash. This can happen everytime a pointer is converted to a reference. It means that you can reduce the risk by removing as much pointers as possible... – paercebal Oct 10 '08 at 20:40
  • 12
    mark has a valid argument. the argument that a pointer could be NULL and you therefor have to check is not real either: if you say a function requires non-NULL, then the caller has to do that. so if the caller doesn't he is invoking undefined behavior. just like mark did with the bad reference – Johannes Schaub - litb Feb 27 '09 at 21:14
  • 1
    Depending on the implementation, hardware and OS, the act of setting a reference variable to an invalid address can an exception. The address 0 may or may not be valid, again depending on hardware and OS. – Pete Kirkham Jul 04 '09 at 09:32
  • 18
    The description is erroneous. This code might or might not create a reference that is NULL. Its behavior is undefined. It might create a perfectly valid reference. It might fail to create any reference at all. – David Schwartz Aug 20 '11 at 11:41
  • 12
    @David Schwartz, if I were talking about the way things had to work according to the standard, you'd be correct. But that's *not* what I'm talking about - I'm talking about actual observed behavior with a very popular compiler, and extrapolating based on my knowledge of typical compilers and CPU architectures to what will *probably* happen. If you believe references to be superior to pointers because they're safer and don't consider that references can be bad, you'll be stumped by a simple problem someday just as I was. – Mark Ransom Aug 22 '11 at 02:11
  • 3
    If you allow undefined behaviour then anything is possible... you can have `1 < 0` , an `int` containing `3.5`, a function that launches missiles. If anything is possible, nothing is remarkable. – M.M Feb 23 '17 at 05:22
  • 4
    @M.M you're missing my point entirely. Many people believe references are *safer* than pointers, and my experience is that this is not the case. It's far too easy to get undefined behavior without realizing it. That is the message I am trying to deliver with this answer. – Mark Ransom Feb 23 '17 at 05:41
  • 8
    Dereferencing a null pointer is wrong. Any program that does that, even to initialize a reference is wrong. If you are initializing a reference from a pointer you should always check that the pointer is valid. Even if this succeeds the underlying object may be deleted at any time leaving the reference to refer to non-existing object, right? What you are saying is good stuff. I think the real issue here is that reference does NOT need to be checked for "nullness" when you see one and pointer should be, at minimum, asserted. – t0rakka Mar 22 '17 at 14:07
  • 1
    Above said, the universally agreed way to track object life-time and ownership reliably in C++ is to use RAII. The std has solid classes for this job with their own tradeoffs. We could be like C# and Java (gross generalization) and just pass everything by a by-value std::shared_ptr but that would be very bloated way to pass parameters so references and pointers still have a role to play. Lately I been gravitating towards passing simple POD types by value instead of const-reference because on target platforms I work on it is more efficient (no indirection and parameters in registers). – t0rakka Mar 22 '17 at 14:20
  • 1
    Example: https://godbolt.org/g/T4Uzvq .. The first, pass-by-value version runs on CPU registers and the second function where parameters are passed by const reference the member data is loaded from memory. The worst case for by-value version is that the caller has to load the values into registers. The by-const-reference version ALWAYS loads the values and in worst case also has to store them in memory even if the values were in registers. LTCG and such may change the picture but overall the trade-off favors the first form. – t0rakka Mar 22 '17 at 14:23
  • 2
    *"C++ doesn't support null references as a concept as you might find in other languages."* - It does now: `optional`. – IInspectable Oct 29 '17 at 00:38
  • 2
    @IInspectable different thing entirely, the question was about plain references. In C# for example I can go `String s = null;` and I get a null reference to a string. Since references can be reassigned in C# this is perfectly reasonable. In C++ references *can't* be reassigned so a null reference would be worthless, and the language makes no attempt to support it. – Mark Ransom Oct 29 '17 at 02:24
  • 1
    [`optional`](http://en.cppreference.com/w/cpp/utility/optional) would have been just that. Except, it doesn't exist. Mostly due to arbitrarily limiting reference semantics, making them very alien to C++ value semantics (as outlined in [this CppCon 2017 talk](https://youtu.be/uYDt1gCDxhM)). – IInspectable Oct 29 '17 at 08:50
  • @Mark Ransom: The problem with this answer is that, in the second paragraph where you say "Any invalid reference raises the spectre of undefined behavior", it sounds like you mean `r = 1` has undefined behaviour, and that the code wood be fine if limited to the first two lines. In fact the second line, `int & r = *p`, has undefined behaviour and could cause a crash (or do anything else) even without `r = 1`. Looking at your comments, I think you do know that, but the current text of your answer is likely to mislead anyone who doesn't already realise this. – Arthur Tacca Oct 13 '18 at 11:32
130

You forgot the most important part:

member-access with pointers uses ->
member-access with references uses .

foo.bar is clearly superior to foo->bar in the same way that vi is clearly superior to Emacs :-)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Orion Edwards
  • 121,657
  • 64
  • 239
  • 328
  • 6
    @Orion Edwards >member-access with pointers uses -> >member-access with references uses . This is not 100% true. You can have a reference to a pointer. In this case you would access members of de-referenced pointer using -> struct Node { Node *next; }; Node *first; // p is a reference to a pointer void foo(Node*&p) { p->next = first; } Node *bar = new Node; foo(bar); -- OP: Are you familiar with the concepts of rvalues and lvalues? –  Sep 12 '08 at 12:57
  • 4
    Smart Pointers have both . (methods on smart pointer class) and -> (methods on underlying type). – JBRWilkinson Apr 09 '14 at 09:11
  • 2
    @user6105 [Orion Edwards](http://stackoverflow.com/users/234) statement is actually 100% true. *"access members of [the] de-referenced pointer"* A pointer does not have any members. The object the pointer refers to has members, and access to those is exactly what `->` provides for references to pointers, just as with the pointer itself. – Max Truxa Apr 15 '15 at 17:37
  • 3
    why is that `.` and `->` has something to do with vi and emacs :) – artm Aug 21 '16 at 00:45
  • 14
    @artM - it was a joke, and probably doesn't make sense to non-native english speakers. My apologies. To explain, whether vi is better than emacs is entirely subjective. Some people think vi is far superior, and others think the exact opposite. Similarly, I think using `.` is better than using `->`, but just like vi vs emacs, it's entirely subjective and you can't prove anything – Orion Edwards Aug 25 '16 at 21:41
  • 1
    `.` syntax is easier to port your C++ to C#, the language you should have been using. – Mark Lakata Aug 02 '18 at 17:07
  • The first half might be true, but hardly ‘the most important’. The other is just opinion. – user3840170 Jan 04 '21 at 16:26
  • 1
    @user3840170 it's a joke :-) This may be hard to believe, but back in the early days of stack overflow (note the answer is dated september 2008) people used to have a sense of humour and it was a nice site to hang out on. To be honest it's hard to believe that some pedant hasn't marked this answer as deleted by now – Orion Edwards Jan 04 '21 at 23:12
88

References are very similar to pointers, but they are specifically crafted to be helpful to optimizing compilers.

  • References are designed such that it is substantially easier for the compiler to trace which reference aliases which variables. Two major features are very important: no "reference arithmetic" and no reassigning of references. These allow the compiler to figure out which references alias which variables at compile time.
  • References are allowed to refer to variables which do not have memory addresses, such as those the compiler chooses to put into registers. If you take the address of a local variable, it is very hard for the compiler to put it in a register.

As an example:

void maybeModify(int& x); // may modify x in some way

void hurtTheCompilersOptimizer(short size, int array[])
{
    // This function is designed to do something particularly troublesome
    // for optimizers. It will constantly call maybeModify on array[0] while
    // adding array[1] to array[2]..array[size-1]. There's no real reason to
    // do this, other than to demonstrate the power of references.
    for (int i = 2; i < (int)size; i++) {
        maybeModify(array[0]);
        array[i] += array[1];
    }
}

An optimizing compiler may realize that we are accessing a[0] and a[1] quite a bunch. It would love to optimize the algorithm to:

void hurtTheCompilersOptimizer(short size, int array[])
{
    // Do the same thing as above, but instead of accessing array[1]
    // all the time, access it once and store the result in a register,
    // which is much faster to do arithmetic with.
    register int a0 = a[0];
    register int a1 = a[1]; // access a[1] once
    for (int i = 2; i < (int)size; i++) {
        maybeModify(a0); // Give maybeModify a reference to a register
        array[i] += a1;  // Use the saved register value over and over
    }
    a[0] = a0; // Store the modified a[0] back into the array
}

To make such an optimization, it needs to prove that nothing can change array[1] during the call. This is rather easy to do. i is never less than 2, so array[i] can never refer to array[1]. maybeModify() is given a0 as a reference (aliasing array[0]). Because there is no "reference" arithmetic, the compiler just has to prove that maybeModify never gets the address of x, and it has proven that nothing changes array[1].

It also has to prove that there are no ways a future call could read/write a[0] while we have a temporary register copy of it in a0. This is often trivial to prove, because in many cases it is obvious that the reference is never stored in a permanent structure like a class instance.

Now do the same thing with pointers

void maybeModify(int* x); // May modify x in some way

void hurtTheCompilersOptimizer(short size, int array[])
{
    // Same operation, only now with pointers, making the
    // optimization trickier.
    for (int i = 2; i < (int)size; i++) {
        maybeModify(&(array[0]));
        array[i] += array[1];
    }
}

The behavior is the same; only now it is much harder to prove that maybeModify does not ever modify array[1], because we already gave it a pointer; the cat is out of the bag. Now it has to do the much more difficult proof: a static analysis of maybeModify to prove it never writes to &x + 1. It also has to prove that it never saves off a pointer that can refer to array[0], which is just as tricky.

Modern compilers are getting better and better at static analysis, but it is always nice to help them out and use references.

Of course, barring such clever optimizations, compilers will indeed turn references into pointers when needed.

EDIT: Five years after posting this answer, I found an actual technical difference where references are different than just a different way of looking at the same addressing concept. References can modify the lifespan of temporary objects in a way that pointers cannot.

F createF(int argument);

void extending()
{
    const F& ref = createF(5);
    std::cout << ref.getArgument() << std::endl;
};

Normally temporary objects such as the one created by the call to createF(5) are destroyed at the end of the expression. However, by binding that object to a reference, ref, C++ will extend the lifespan of that temporary object until ref goes out of scope.

Cort Ammon
  • 10,221
  • 31
  • 45
  • True, the body does have to be visible. However, determining that `maybeModify` does not take the address of anything related to `x` is substantially easier than proving that a bunch of pointer arithmetic does not occur. – Cort Ammon Sep 11 '13 at 04:27
  • I believe the optimizer already does that "a bunch of pointer arithemetic does not occur" check for a bunch of other reasons. – Ben Voigt Sep 11 '13 at 04:32
  • "References are very similar to pointers" - semantically, in appropriate contexts - but in terms of generated code, only in some implementations and not through any definition/requirement. I know you've pointed this out, and I don't disagree with any of your post in practical terms, but we have too many problems already with people reading too much into shorthand descriptions like 'references are like/usually implemented as pointers'. – underscore_d Oct 11 '15 at 17:31
  • 1
    I have a feeling that someone wrongly flagged as obsolete a comment along the lines of `void maybeModify(int& x) { 1[&x]++; }`, which the other comments above are discussing – Ben Voigt Dec 03 '15 at 23:28
83

Actually, a reference is not really like a pointer.

A compiler keeps "references" to variables, associating a name with a memory address; that's its job to translate any variable name to a memory address when compiling.

When you create a reference, you only tell the compiler that you assign another name to the pointer variable; that's why references cannot "point to null", because a variable cannot be, and not be.

Pointers are variables; they contain the address of some other variable, or can be null. The important thing is that a pointer has a value, while a reference only has a variable that it is referencing.

Now some explanation of real code:

int a = 0;
int& b = a;

Here you are not creating another variable that points to a; you are just adding another name to the memory content holding the value of a. This memory now has two names, a and b, and it can be addressed using either name.

void increment(int& n)
{
    n = n + 1;
}

int a;
increment(a);

When calling a function, the compiler usually generates memory spaces for the arguments to be copied to. The function signature defines the spaces that should be created and gives the name that should be used for these spaces. Declaring a parameter as a reference just tells the compiler to use the input variable memory space instead of allocating a new memory space during the method call. It may seem strange to say that your function will be directly manipulating a variable declared in the calling scope, but remember that when executing compiled code, there is no more scope; there is just plain flat memory, and your function code could manipulate any variables.

Now there may be some cases where your compiler may not be able to know the reference when compiling, like when using an extern variable. So a reference may or may not be implemented as a pointer in the underlying code. But in the examples I gave you, it will most likely not be implemented with a pointer.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Vincent Robert
  • 35,564
  • 14
  • 82
  • 119
  • 2
    A reference is a reference to l-value, not necessarily to a variable. Because of that, it's much closer to a pointer than to a real alias (a compile-time construct). Examples of expressions that can be referenced are *p or even *p++ –  Mar 02 '09 at 16:27
  • 6
    Right, I was just pointing the fact that a reference may not always push a new variable on the stack the way a new pointer will. – Vincent Robert Mar 03 '09 at 20:36
  • 4
    @VincentRobert: It will act the same as a pointer... if the function is inlined, both reference and pointer will be optimized away. If there's a function call, the address of the object will need to be passed to the function. – Ben Voigt Feb 13 '12 at 23:08
  • 1
    int *p = NULL; int &r=*p; reference pointing to NULL; if(r){} -> boOm ;) – uss Oct 04 '15 at 12:37
  • 2
    This focus on the compile stage seems nice, until you remember that references can be passed around at runtime, at which point static aliasing goes out of the window. (And then, references are _usually_ implemented as pointers, but the standard doesn't require this method.) – underscore_d Oct 11 '15 at 17:35
  • @sree> wrong. That sample is just not valid c++. Some compilers will warn about it. Some will even just remove the statement it altogether (clang does that in some circumstances), making any assertion about what you get wrong. What you get is undefined. – spectras Jan 15 '21 at 22:14
  • @uss It's actually just `int *p = 0; int &r=*p;` that's BOOM. The `if` comes after the explosion. – Spencer Oct 06 '22 at 19:27
  • @VincentRobert: "When you create a reference, you only tell the compiler that you assign another name to the pointer variable; that's why references cannot **point to null**". When you say this and follow up by saying "because a variable cannot be, and not be", do you mean in literal sense that "we are asking the reference to alias a pointer that is not created at all and hence we cannot have such a reference?" – Floatoss Apr 17 '23 at 11:58
48

A reference can never be NULL.

Cole Tobin
  • 9,206
  • 15
  • 49
  • 74
  • 12
    See Mark Ransom's answer for a counter-example. This is the most often asserted myth about references, but it is a myth. The only guarantee that you have by the standard is, that you immediately have UB when you have a NULL reference. But that is akin to saying "This car is safe, it can never get off the road. (We don't take any responsibility for what may happen if you steer it off the road anyway. It might just explode.)" – cmaster - reinstate monica Jun 13 '14 at 11:36
  • 20
    @cmaster: **In a valid program**, a reference cannot be null. But a pointer can. This is not a myth, this is a fact. – user541686 Aug 08 '14 at 04:42
  • 9
    @Mehrdad Yes, valid programs stay on the road. But there is no traffic barrier to enforce that your program actually does. Large parts of the road are actually missing markings. So it's extremely easy to get off the road at night. And it is crucial for debugging such bugs that you *know* this can happen: the null reference can propagate before it crashes your program, just like a null pointer can. And when it does you have code like `void Foo::bar() { virtual_baz(); }` that segfaults. If you are not aware that references may be null, you can't trace the null back to its origin. – cmaster - reinstate monica Dec 29 '14 at 10:43
  • 4
    int *p = NULL; int &r=*p; reference pointing to NULL; if(r){} -> boOm ;) – – uss Oct 04 '15 at 12:43
  • 13
    @sree `int &r=*p;` is undefined behavior. At that point, you don't have a "reference pointing to NULL," you have a program that *can no longer be reasoned about **at all**.* – cdhowie Mar 28 '17 at 18:46
  • 1
    @cdhowie Wow... @sree wasn't implying that `int *p = NULL; int &r=*p;` was good practice, they were just giving an example of how a reference can indeed be `NULL`. The UB's purple dragons won't appear until you **use** the null reference, just as the UB doesn't happen with null pointers until you "dereference" the pointer. But even though it's UB, in both cases, it's pretty well expected that the UB will result in a SIGSEGV or memory access exception, unless you're working on an embedded system, in which case you very well may be trying to access something that really is at address 0. – phonetagger Jan 26 '18 at 23:09
  • 3
    @phonetagger On most implementations, yes, you won't see a crash until the reference is used. This does not invalidate my statement though -- according to the standard, UB is invoked when the reference is seated. Once you have bound an invalid object to a reference, the behavior of the program is undefined from that point on. The possibility that it works as intended until the reference is used is certainly one possible outcome of UB. Another compiler and/or architecture may exhibit different results. – cdhowie Jan 29 '18 at 02:02
  • 3
    @phonetagger Hopefully [this example](http://coliru.stacked-crooked.com/a/4d459d4219a35ae9) drives home that we've entered the realm of UB. We create a reference seated to an invalid (null) object. The program never crashes, but it produces an "incorrect" result because the optimizer has assumed that UB will not occur. Note that compiling with `-O0` reverses the output of the program! At higher optimization levels, we can't even ask if the address of a reference is null, because the optimizer knows that no reference is allowed to be null; `&x != nullptr` on a reference `x` is a tautology! – cdhowie Jan 30 '18 at 02:44
  • 1
    @phonetagger NB that in the linked example, _we never use the (invalid) referent object!_ Nevertheless, UB is manifest as soon as we seat the reference. – cdhowie Jan 30 '18 at 02:46
  • 1
    cdhowie that the same with pointers actually, if you know what you do, you always do things correctly, pointer are perfectly safe... And if you make an error they are not. References are the same. And because you need pointers in programs anyway and you'll want reference in the rest of the code, you are quite likely to assign a pointer to a reference at some point making the difference between both concept in term of safety moot. – Nicolas Bousquet Nov 17 '18 at 21:50
  • Since references can’t be null, the compiler can assume they aren’t. If (&ref == NuLL) can just evaluate to false without executing any code. So yo can’t even check that it’s null. – gnasher729 Jul 08 '23 at 07:11
38

There is a semantic difference that may appear esoteric if you are not familiar with studying computer languages in an abstract or even academic fashion.

At the highest-level, the idea of references is that they are transparent "aliases". Your computer may use an address to make them work, but you're not supposed to worry about that: you're supposed to think of them as "just another name" for an existing object and the syntax reflects that. They are stricter than pointers so your compiler can more reliably warn you when you about to create a dangling reference, than when you are about to create a dangling pointer.

Beyond that, there are of course some practical differences between pointers and references. The syntax to use them is obviously different, and you cannot "re-seat" references, have references to nothingness, or have pointers to references.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
37

While both references and pointers are used to indirectly access another value, there are two important differences between references and pointers. The first is that a reference always refers to an object: It is an error to define a reference without initializing it. The behavior of assignment is the second important difference: Assigning to a reference changes the object to which the reference is bound; it does not rebind the reference to another object. Once initialized, a reference always refers to the same underlying object.

Consider these two program fragments. In the first, we assign one pointer to another:

int ival = 1024, ival2 = 2048;
int *pi = &ival, *pi2 = &ival2;
pi = pi2;    // pi now points to ival2

After the assignment, ival, the object addressed by pi remains unchanged. The assignment changes the value of pi, making it point to a different object. Now consider a similar program that assigns two references:

int &ri = ival, &ri2 = ival2;
ri = ri2;    // assigns ival2 to ival

This assignment changes ival, the value referenced by ri, and not the reference itself. After the assignment, the two references still refer to their original objects, and the value of those objects is now the same as well.

Kunal Vyas
  • 1,499
  • 1
  • 23
  • 40
30

A reference is an alias for another variable whereas a pointer holds the memory address of a variable. References are generally used as function parameters so that the passed object is not the copy but the object itself.

    void fun(int &a, int &b); // A common usage of references.
    int a = 0;
    int &b = a; // b is an alias for a. Not so common to use. 
fatma.ekici
  • 2,787
  • 4
  • 28
  • 30
26

The direct answer

What is a reference in C++? Some specific instance of type that is not an object type.

What is a pointer in C++? Some specific instance of type that is an object type.

From the ISO C++ definition of object type:

An object type is a (possibly cv-qualified) type that is not a function type, not a reference type, and not cv void.

It may be important to know, object type is a top-level category of the type universe in C++. Reference is also a top-level category. But pointer is not.

Pointers and references are mentioned together in the context of compound type. This is basically due to the nature of the declarator syntax inherited from (and extended) C, which has no references. (Besides, there are more than one kind of declarator of references since C++ 11, while pointers are still "unityped": &+&& vs. *.) So drafting a language specific by "extension" with similar style of C in this context is somewhat reasonable. (I will still argue that the syntax of declarators wastes the syntactic expressiveness a lot, makes both human users and implementations frustrating. Thus, all of them are not qualified to be built-in in a new language design. This is a totally different topic about PL design, though.)

Otherwise, it is insignificant that pointers can be qualified as a specific sorts of types with references together. They simply share too few common properties besides the syntax similarity, so there is no need to put them together in most cases.

Note the statements above only mentions "pointers" and "references" as types. There are some interested questions about their instances (like variables). There also come too many misconceptions.

The differences of the top-level categories can already reveal many concrete differences not tied to pointers directly:

  • Object types can have top-level cv qualifiers. References cannot.
  • Variable of object types do occupy storage as per the abstract machine semantics. Reference do not necessary occupy storage (see the section about misconceptions below for details).
  • ...

A few more special rules on references:

  • Compound declarators are more restrictive on references.
  • References can collapse.
    • Special rules on && parameters (as the "forwarding references") based on reference collapsing during template parameter deduction allow "perfect forwarding" of parameters.
  • References have special rules in initialization. The lifetime of variable declared as a reference type can be different to ordinary objects via extension.
    • BTW, a few other contexts like initialization involving std::initializer_list follows some similar rules of reference lifetime extension. It is another can of worms.
  • ...

The misconceptions

Syntactic sugar

I know references are syntactic sugar, so code is easier to read and write.

Technically, this is plain wrong. References are not syntactic sugar of any other features in C++, because they cannot be exactly replaced by other features without any semantic differences.

(Similarly, lambda-expressions are not syntactic sugar of any other features in C++ because it cannot be precisely simulated with "unspecified" properties like the declaration order of the captured variables, which may be important because the initialization order of such variables can be significant.)

C++ only has a few kinds of syntactic sugars in this strict sense. One instance is (inherited from C) the built-in (non-overloaded) operator [], which is defined exactly having same semantic properties of specific forms of combination over built-in operator unary * and binary +.

Storage

So, a pointer and a reference both use the same amount of memory.

The statement above is simply wrong. To avoid such misconceptions, look at the ISO C++ rules instead:

From [intro.object]/1:

... An object occupies a region of storage in its period of construction, throughout its lifetime, and in its period of destruction. ...

From [dcl.ref]/4:

It is unspecified whether or not a reference requires storage.

Note these are semantic properties.

Pragmatics

Even that pointers are not qualified enough to be put together with references in the sense of the language design, there are still some arguments making it debatable to make choice between them in some other contexts, for example, when making choices on parameter types.

But this is not the whole story. I mean, there are more things than pointers vs references you have to consider.

If you don't have to stick on such over-specific choices, in most cases the answer is short: you do not have the necessity to use pointers, so you don't. Pointers are usually bad enough because they imply too many things you don't expect and they will rely on too many implicit assumptions undermining the maintainability and (even) portability of the code. Unnecessarily relying on pointers is definitely a bad style and it should be avoided in the sense of modern C++. Reconsider your purpose and you will finally find that pointer is the feature of last sorts in most cases.

  • Sometimes the language rules explicitly require specific types to be used. If you want to use these features, obey the rules.
    • Copy constructors require specific types of cv-& reference type as the 1st parameter type. (And usually it should be const qualified.)
    • Move constructors require specific types of cv-&& reference type as the 1st parameter type. (And usually there should be no qualifiers.)
    • Specific overloads of operators require reference or non reference types. For example:
      • Overloaded operator= as special member functions requires reference types similar to 1st parameter of copy/move constructors.
      • Postfix ++ requires dummy int.
      • ...
  • If you know pass-by-value (i.e. using non-reference types) is sufficient, use it directly, particularly when using an implementation supporting C++17 mandated copy elision. (Warning: However, to exhaustively reason about the necessity can be very complicated.)
  • If you want to operate some handles with ownership, use smart pointers like unique_ptr and shared_ptr (or even with homebrew ones by yourself if you require them to be opaque), rather than raw pointers.
  • If you are doing some iterations over a range, use iterators (or some ranges which are not provided by the standard library yet), rather than raw pointers unless you are convinced raw pointers will do better (e.g. for less header dependencies) in very specific cases.
  • If you know pass-by-value is sufficient and you want some explicit nullable semantics, use wrapper like std::optional, rather than raw pointers.
  • If you know pass-by-value is not ideal for the reasons above, and you don't want nullable semantics, use {lvalue, rvalue, forwarding}-references.
  • Even when you do want semantics like traditional pointer, there are often something more appropriate, like observer_ptr in Library Fundamental TS.

The only exceptions cannot be worked around in the current language:

  • When you are implementing smart pointers above, you may have to deal with raw pointers.
  • Specific language-interoperation routines require pointers, like operator new. (However, cv-void* is still quite different and safer compared to the ordinary object pointers because it rules out unexpected pointer arithmetics unless you are relying on some non conforming extension on void* like GNU's.)
  • Function pointers can be converted from lambda expressions without captures, while function references cannot. You have to use function pointers in non-generic code for such cases, even you deliberately do not want nullable values.

So, in practice, the answer is so obvious: when in doubt, avoid pointers. You have to use pointers only when there are very explicit reasons that nothing else is more appropriate. Except a few exceptional cases mentioned above, such choices are almost always not purely C++-specific (but likely to be language-implementation-specific). Such instances can be:

  • You have to serve to old-style (C) APIs.
  • You have to meet the ABI requirements of specific C++ implementations.
  • You have to interoperate at runtime with different language implementations (including various assemblies, language runtime and FFI of some high-level client languages) based on assumptions of specific implementations.
  • You have to improve efficiency of the translation (compilation & linking) in some extreme cases.
  • You have to avoid symbol bloat in some extreme cases.

Language neutrality caveats

If you come to see the question via some Google search result (not specific to C++), this is very likely to be the wrong place.

References in C++ is quite "odd", as it is essentially not first-class: they will be treated as the objects or the functions being referred to so they have no chance to support some first-class operations like being the left operand of the member access operator independently to the type of the referred object. Other languages may or may not have similar restrictions on their references.

References in C++ will likely not preserve the meaning across different languages. For example, references in general do not imply nonnull properties on values like they in C++, so such assumptions may not work in some other languages (and you will find counterexamples quite easily, e.g. Java, C#, ...).

There can still be some common properties among references in different programming languages in general, but let's leave it for some other questions in SO.

(A side note: the question may be significant earlier than any "C-like" languages are involved, like ALGOL 68 vs. PL/I.)

FrankHB
  • 2,297
  • 23
  • 19
  • Nitpick: "use iterators rather than pointers" pointers model the iterator concept. E.g. a conforming implementation can choose `std::vector::iterator` to be an alias for `T*` – Caleth Sep 30 '22 at 08:35
23

This is based on the tutorial. What is written makes it more clear:

>>> The address that locates a variable within memory is
    what we call a reference to that variable. (5th paragraph at page 63)

>>> The variable that stores the reference to another
    variable is what we call a pointer. (3rd paragraph at page 64)

Simply to remember that,

>>> reference stands for memory location
>>> pointer is a reference container (Maybe because we will use it for
several times, it is better to remember that reference.)

What's more, as we can refer to almost any pointer tutorial, a pointer is an object that is supported by pointer arithmetic which makes pointer similar to an array.

Look at the following statement,

int Tom(0);
int & alias_Tom = Tom;

alias_Tom can be understood as an alias of a variable (different with typedef, which is alias of a type) Tom. It is also OK to forget the terminology of such statement is to create a reference of Tom.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Life
  • 449
  • 3
  • 9
  • 1
    And if a class has a reference variable, It should be initialized with either a nullptr or a valid object in the initialization list. – Misgevolution Jun 15 '15 at 17:32
  • 1
    The wording in this answer is too confusing for it to be of much real use. Also, @Misgevolution, are you seriously recommending to readers to initialise a reference with a `nullptr`? Have you actually read any other part of this thread, or...? – underscore_d Oct 11 '15 at 17:27
  • 1
    My bad, sorry for that stupid thing I said. I must have been sleep deprived by that time. 'initialize with nullptr' is totally wrong. – Misgevolution Oct 11 '15 at 18:09
23

It doesn't matter how much space it takes up since you can't actually see any side effect (without executing code) of whatever space it would take up.

On the other hand, one major difference between references and pointers is that temporaries assigned to const references live until the const reference goes out of scope.

For example:

class scope_test
{
public:
    ~scope_test() { printf("scope_test done!\n"); }
};

...

{
    const scope_test &test= scope_test();
    printf("in scope\n");
}

will print:

in scope
scope_test done!

This is the language mechanism that allows ScopeGuard to work.

MSN
  • 53,214
  • 7
  • 75
  • 105
  • 1
    You can't take the address of a reference, but that doesn't mean that they don't physically take up space. Barring optimisations, they most certainly can. – Lightness Races in Orbit Apr 24 '11 at 16:27
  • 3
    Impact notwithstanding, "A reference on the stack doesn't take up any space at all" is patently false. – Lightness Races in Orbit Apr 25 '11 at 23:09
  • 1
    @Tomalak, well, that depends also on the compiler. But yes, saying that is a bit confusing. I suppose it would be less confusing to just remove that. – MSN Apr 26 '11 at 21:52
  • 1
    In any given specific case it may or it may not. So "it does not" as a categorical assertion is wrong. That's what I'm saying. :) [I can't remember what the standard says on the issue; the rules of reference members may impart a general rule of "references may take up space", but I don't have my copy of the standard with me here on the beach :D] – Lightness Races in Orbit Apr 26 '11 at 22:22
21

A reference is not another name given to some memory. It's a immutable pointer that is automatically de-referenced on usage. Basically it boils down to:

int& j = i;

It internally becomes

int* const j = &i;
Ryan
  • 4,594
  • 1
  • 32
  • 35
tanweer alam
  • 437
  • 4
  • 6
  • 15
    This isn't what the C++ Standard says, and it is not required for the compiler to implement references in the way described by your answer. – jogojapan Feb 26 '13 at 05:22
  • @jogojapan: Any way that is valid for a C++ compiler to implement a reference is also a valid way for it to implement a `const` pointer. That flexibility doesn't prove that there is a difference between a reference and a pointer. – Ben Voigt Aug 26 '15 at 23:00
  • 2
    @BenVoigt It may be true that any valid implementation of one is also a valid implementation of the other, but that doesn't follow in an obvious way from the definitions of these two concepts. A good answer would have started from the definitions, and demonstrated why the claim about the two being ultimately the same is true. This answer seems to be some sort of comment on some of the other answers. – jogojapan Aug 26 '15 at 23:41
  • A reference **is** another name given to an object. The compiler is allowed to have any kind of implementation, as long as you can't tell the difference, this is known as the "as-if" rule. The important part here is that you can't tell the difference. If you can discover that a pointer does not have storage, the compiler is in error. If you can discover that a reference does not have storage, the compiler is still conformant. – sp2danny Sep 06 '17 at 14:52
20

A reference to a pointer is possible in C++, but the reverse is not possible means a pointer to a reference isn't possible. A reference to a pointer provides a cleaner syntax to modify the pointer. Look at this example:

#include<iostream>
using namespace std;

void swap(char * &str1, char * &str2)
{
  char *temp = str1;
  str1 = str2;
  str2 = temp;
}

int main()
{
  char *str1 = "Hi";
  char *str2 = "Hello";
  swap(str1, str2);
  cout<<"str1 is "<<str1<<endl;
  cout<<"str2 is "<<str2<<endl;
  return 0;
}

And consider the C version of the above program. In C you have to use pointer to pointer (multiple indirection), and it leads to confusion and the program may look complicated.

#include<stdio.h>
/* Swaps strings by swapping pointers */
void swap1(char **str1_ptr, char **str2_ptr)
{
  char *temp = *str1_ptr;
  *str1_ptr = *str2_ptr;
  *str2_ptr = temp;
}

int main()
{
  char *str1 = "Hi";
  char *str2 = "Hello";
  swap1(&str1, &str2);
  printf("str1 is %s, str2 is %s", str1, str2);
  return 0;
}

Visit the following for more information about reference to pointer:

As I said, a pointer to a reference isn't possible. Try the following program:

#include <iostream>
using namespace std;

int main()
{
   int x = 10;
   int *ptr = &x;
   int &*ptr1 = ptr;
}
Destructor
  • 14,123
  • 11
  • 61
  • 126
18

I use references unless I need either of these:

  • Null pointers can be used as a sentinel value, often a cheap way to avoid function overloading or use of a bool.

  • You can do arithmetic on a pointer. For example, p += offset;

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Aardvark
  • 8,474
  • 7
  • 46
  • 64
18

There is one fundamental difference between pointers and references that I didn't see anyone had mentioned: references enable pass-by-reference semantics in function arguments. Pointers, although it is not visible at first do not: they only provide pass-by-value semantics. This has been very nicely described in this article.

Regards, &rzej

Andrzej
  • 5,027
  • 27
  • 36
  • 1
    References and pointers are both handles. They both give you the semantic where your *object* is passed by reference, but the *handle* is copied. No difference. (There are other ways to have handles too, such as a key for lookup in a dictionary) – Ben Voigt Nov 07 '13 at 17:16
  • I also used to think like this. But see the linked article describing why it is not so. – Andrzej Nov 12 '13 at 09:08
  • 2
    @Andrzj: That's just a very long version of the single sentence in my comment: **The handle is copied.** – Ben Voigt Nov 12 '13 at 15:10
  • I need more explanation on this "The handle is copied". I understand some basic idea but I think physically the reference and pointer both point the memory location of variable. Is it like alias stores the value variable and updates it as value of variable is change or something else? I'm novice, and please don't flag it as a stupid question. – Asim Dec 11 '13 at 23:13
  • 1
    @Andrzej False. In both cases, pass-by-value is occurring. The reference is passed by value and the pointer is passed by value. Saying otherwise confuses newbies. – Miles Rout Apr 27 '14 at 09:28
  • Stands to reason whether pass by reference is really such a good idea. I prefer being able to see from the function call itself what that function can modify and what not. – cmaster - reinstate monica Jun 13 '14 at 11:41
17

Another difference is that you can have pointers to a void type (and it means pointer to anything) but references to void are forbidden.

int a;
void * p = &a; // ok
void & p = a;  //  forbidden

I can't say I'm really happy with this particular difference. I would much prefer it would be allowed with the meaning reference to anything with an address and otherwise the same behavior for references. It would allow to define some equivalents of C library functions like memcpy using references.

kriss
  • 23,497
  • 17
  • 97
  • 116
17

At the risk of adding to confusion, I want to throw in some input, I'm sure it mostly depends on how the compiler implements references, but in the case of gcc the idea that a reference can only point to a variable on the stack is not actually correct, take this for example:

#include <iostream>
int main(int argc, char** argv) {
    // Create a string on the heap
    std::string *str_ptr = new std::string("THIS IS A STRING");
    // Dereference the string on the heap, and assign it to the reference
    std::string &str_ref = *str_ptr;
    // Not even a compiler warning! At least with gcc
    // Now lets try to print it's value!
    std::cout << str_ref << std::endl;
    // It works! Now lets print and compare actual memory addresses
    std::cout << str_ptr << " : " << &str_ref << std::endl;
    // Exactly the same, now remember to free the memory on the heap
    delete str_ptr;
}

Which outputs this:

THIS IS A STRING
0xbb2070 : 0xbb2070

If you notice even the memory addresses are exactly the same, meaning the reference is successfully pointing to a variable on the heap! Now if you really want to get freaky, this also works:

int main(int argc, char** argv) {
    // In the actual new declaration let immediately de-reference and assign it to the reference
    std::string &str_ref = *(new std::string("THIS IS A STRING"));
    // Once again, it works! (at least in gcc)
    std::cout << str_ref;
    // Once again it prints fine, however we have no pointer to the heap allocation, right? So how do we free the space we just ignorantly created?
    delete &str_ref;
    /*And, it works, because we are taking the memory address that the reference is
    storing, and deleting it, which is all a pointer is doing, just we have to specify
    the address with '&' whereas a pointer does that implicitly, this is sort of like
    calling delete &(*str_ptr); (which also compiles and runs fine).*/
}

Which outputs this:

THIS IS A STRING

Therefore a reference IS a pointer under the hood, they both are just storing a memory address, where the address is pointing to is irrelevant, what do you think would happen if I called std::cout << str_ref; AFTER calling delete &str_ref? Well, obviously it compiles fine, but causes a segmentation fault at runtime because it's no longer pointing at a valid variable, we essentially have a broken reference that still exists (until it falls out of scope), but is useless.

In other words, a reference is nothing but a pointer that has the pointer mechanics abstracted away, making it safer and easier to use (no accidental pointer math, no mixing up '.' and '->', etc.), assuming you don't try any nonsense like my examples above ;)

Now regardless of how a compiler handles references, it will always have some kind of pointer under the hood, because a reference must refer to a specific variable at a specific memory address for it to work as expected, there is no getting around this (hence the term 'reference').

The only major rule that's important to remember with references is that they must be defined at the time of declaration (with the exception of a reference in a header, in that case it must be defined in the constructor, after the object it's contained in is constructed it's too late to define it).

Remember, my examples above are just that, examples demonstrating what a reference is, you would never want to use a reference in those ways! For proper usage of a reference there are plenty of answers on here already that hit the nail on the head

Tory
  • 477
  • 5
  • 10
15

Also, a reference that is a parameter to a function that is inlined may be handled differently than a pointer.

void increment(int *ptrint) { (*ptrint)++; }
void increment(int &refint) { refint++; }
void incptrtest()
{
    int testptr=0;
    increment(&testptr);
}
void increftest()
{
    int testref=0;
    increment(testref);
}

Many compilers when inlining the pointer version one will actually force a write to memory (we are taking the address explicitly). However, they will leave the reference in a register which is more optimal.

Of course, for functions that are not inlined the pointer and reference generate the same code and it's always better to pass intrinsics by value than by reference if they are not modified and returned by the function.

Adisak
  • 6,708
  • 38
  • 46
14

This program might help in comprehending the answer of the question. This is a simple program of a reference "j" and a pointer "ptr" pointing to variable "x".

#include<iostream>

using namespace std;

int main()
{
int *ptr=0, x=9; // pointer and variable declaration
ptr=&x; // pointer to variable "x"
int & j=x; // reference declaration; reference to variable "x"

cout << "x=" << x << endl;

cout << "&x=" << &x << endl;

cout << "j=" << j << endl;

cout << "&j=" << &j << endl;

cout << "*ptr=" << *ptr << endl;

cout << "ptr=" << ptr << endl;

cout << "&ptr=" << &ptr << endl;
    getch();
}

Run the program and have a look at the output and you'll understand.

Also, spare 10 minutes and watch this video: https://www.youtube.com/watch?v=rlJrrGV0iOg

Arlene Batada
  • 1,565
  • 2
  • 11
  • 11
14

Another interesting use of references is to supply a default argument of a user-defined type:

class UDT
{
public:
   UDT() : val_d(33) {};
   UDT(int val) : val_d(val) {};
   virtual ~UDT() {};
private:
   int val_d;
};

class UDT_Derived : public UDT
{
public:
   UDT_Derived() : UDT() {};
   virtual ~UDT_Derived() {};
};

class Behavior
{
public:
   Behavior(
      const UDT &udt = UDT()
   )  {};
};

int main()
{
   Behavior b; // take default

   UDT u(88);
   Behavior c(u);

   UDT_Derived ud;
   Behavior d(ud);

   return 1;
}

The default flavor uses the 'bind const reference to a temporary' aspect of references.

Don Wakefield
  • 8,693
  • 3
  • 36
  • 54
13

I feel like there is yet another point that hasn't been covered here.

Unlike the pointers, references are syntactically equivalent to the object they refer to, i.e. any operation that can be applied to an object works for a reference, and with the exact same syntax (the exception is of course the initialization).

While this may appear superficial, I believe this property is crucial for a number of C++ features, for example:

  • Templates. Since template parameters are duck-typed, syntactic properties of a type is all that matters, so often the same template can be used with both T and T&.
    (or std::reference_wrapper<T> which still relies on an implicit cast to T&)
    Templates that cover both T& and T&& are even more common.

  • Lvalues. Consider the statement str[0] = 'X'; Without references it would only work for c-strings (char* str). Returning the character by reference allows user-defined classes to have the same notation.

  • Copy constructors. Syntactically it makes sense to pass objects to copy constructors, and not pointers to objects. But there is just no way for a copy constructor to take an object by value - it would result in a recursive call to the same copy constructor. This leaves references as the only option here.

  • Operator overloads. With references it is possible to introduce indirection to an operator call - say, operator+(const T& a, const T& b) while retaining the same infix notation. This also works for regular overloaded functions.

These points empower a considerable part of C++ and the standard library so this is quite a major property of references.

Ap31
  • 3,244
  • 1
  • 18
  • 25
12

There is a very important non-technical difference between pointers and references: An argument passed to a function by pointer is much more visible than an argument passed to a function by non-const reference. For example:

void fn1(std::string s);
void fn2(const std::string& s);
void fn3(std::string& s);
void fn4(std::string* s);

void bar() {
    std::string x;
    fn1(x);  // Cannot modify x
    fn2(x);  // Cannot modify x (without const_cast)
    fn3(x);  // CAN modify x!
    fn4(&x); // Can modify x (but is obvious about it)
}

Back in C, a call that looks like fn(x) can only be passed by value, so it definitely cannot modify x; to modify an argument you would need to pass a pointer fn(&x). So if an argument wasn't preceded by an & you knew it would not be modified. (The converse, & means modified, was not true because you would sometimes have to pass large read-only structures by const pointer.)

Some argue that this is such a useful feature when reading code, that pointer parameters should always be used for modifiable parameters rather than non-const references, even if the function never expects a nullptr. That is, those people argue that function signatures like fn3() above should not be allowed. Google's C++ style guidelines are an example of this.

Donald Duck
  • 8,409
  • 22
  • 75
  • 99
Arthur Tacca
  • 8,833
  • 2
  • 31
  • 49
12

A reference is a const pointer. int * const a = &b is the same as int& a = b. This is why there's is no such thing as a const reference, because it is already const, whereas a reference to const is const int * const a. When you compile using -O0, the compiler will place the address of b on the stack in both situations, and as a member of a class, it will also be present in the object on the stack/heap identically to if you had declared a const pointer. With -Ofast, it is free to optimise this out. A const pointer and reference are both optimised away.

Unlike a const pointer, there is no way to take the address of the reference itself, as it will be interpreted as the address of the variable it references. Because of this, on -Ofast, the const pointer representing the reference (the address of the variable being referenced) will always be optimised off the stack, but if the program absolutely needs the address of an actual const pointer (the address of the pointer itself, not the address it points to) i.e. you print the address of the const pointer, then the const pointer will be placed on the stack so that it has an address.

Otherwise it is identical i.e. when you print the that address it points to:

#include <iostream>

int main() {
  int a =1;
  int* b = &a;
  std::cout << b ;
}

int main() {
  int a =1;
  int& b = a;
  std::cout << &b ;
}
they both have the same assembly output
-Ofast:
main:
        sub     rsp, 24
        mov     edi, OFFSET FLAT:_ZSt4cout
        lea     rsi, [rsp+12]
        mov     DWORD PTR [rsp+12], 1
        call    std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<void const*>(void const*)
        xor     eax, eax
        add     rsp, 24
        ret
--------------------------------------------------------------------
-O0:
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     DWORD PTR [rbp-12], 1
        lea     rax, [rbp-12]
        mov     QWORD PTR [rbp-8], rax
        mov     rax, QWORD PTR [rbp-8]
        mov     rsi, rax
        mov     edi, OFFSET FLAT:_ZSt4cout
        call    std::basic_ostream<char, std::char_traits<char> >::operator<<(void const*)
        mov     eax, 0
        leave
        ret

The pointer has been optimised off the stack, and the pointer isn't even dereferenced on -Ofast in both cases, instead it uses a compile time value.

As members of an object they are identical on -O0 through -Ofast.

#include <iostream>
int b=1;
struct A {int* i=&b; int& j=b;};
A a;
int main() {
  std::cout << &a.j << &a.i;
}

The address of b is stored twice in the object. 

a:
        .quad   b
        .quad   b
        mov     rax, QWORD PTR a[rip+8] //&a.j
        mov     esi, OFFSET FLAT:a //&a.i

When you pass by reference, on -O0, you pass the address of the variable referenced, so it is identical to passing by pointer i.e. the address the const pointer contains. On -Ofast this is optimised out by the compiler in an inline call if the function can be inlined, as the dynamic scope is known, but in the function definition, the parameter is always dereferenced as a pointer (expecting the address of the variable being referenced by the reference) where it may be used by another translation unit and the dynamic scope is unknown to the compiler, unless of course the function is declared as a static function, then it can't be used outside of the translation unit and then it passes by value so long as it isn't modified in the function by reference, then it will pass the address of the variable being referenced by the reference that you're passing, and on -Ofast this will be passed in a register and kept off of the stack if there are enough volatile registers in the calling convention.

Lewis Kelsey
  • 4,129
  • 1
  • 32
  • 42
11

Maybe some metaphors will help; In the context of your desktop screenspace -

  • A reference requires you to specify an actual window.
  • A pointer requires the location of a piece of space on screen that you assure it will contain zero or more instances of that window type.
George R
  • 3,784
  • 3
  • 34
  • 38
8

Difference between pointer and reference

A pointer can be initialized to 0 and a reference not. In fact, a reference must also refer to an object, but a pointer can be the null pointer:

int* p = 0;

But we can’t have int& p = 0; and also int& p=5 ;.

In fact to do it properly, we must have declared and defined an object at the first then we can make a reference to that object, so the correct implementation of the previous code will be:

Int x = 0;
Int y = 5;
Int& p = x;
Int& p1 = y;

Another important point is that is we can make the declaration of the pointer without initialization however no such thing can be done in case of reference which must make a reference always to variable or object. However such use of a pointer is risky so generally we check if the pointer is actually is pointing to something or not. In case of a reference no such check is necessary, because we know already that referencing to an object during declaration is mandatory.

Another difference is that pointer can point to another object however reference is always referencing to the same object, let’s take this example:

Int a = 6, b = 5;
Int& rf = a;

Cout << rf << endl; // The result we will get is 6, because rf is referencing to the value of a.

rf = b;
cout << a << endl; // The result will be 5 because the value of b now will be stored into the address of a so the former value of a will be erased

Another point: When we have a template like an STL template such kind of a class template will always return a reference, not a pointer, to make easy reading or assigning new value using operator []:

Std ::vector<int>v(10); // Initialize a vector with 10 elements
V[5] = 5; // Writing the value 5 into the 6 element of our vector, so if the returned type of operator [] was a pointer and not a reference we should write this *v[5]=5, by making a reference we overwrite the element by using the assignment "="
Community
  • 1
  • 1
dhokar.w
  • 386
  • 3
  • 6
  • 1
    We still can have `const int& i = 0`. – Revolver_Ocelot Jan 06 '17 at 14:24
  • 1
    In this case the reference will be used only in read we can't modify this const reference even using "const_cast" because "const_cast" accept only pointer not reference. – dhokar.w Jan 06 '17 at 14:37
  • 1
    const_cast works with references pretty well: http://coliru.stacked-crooked.com/a/eebb454ab2cfd570 – Revolver_Ocelot Jan 06 '17 at 16:52
  • 1
    you are making a cast to reference not casting a reference try this; const int& i=; const_cast(i); i try to throw away the constness of the reference to make possible write and assignement of new value to the reference but this is not possible . please focus !! – dhokar.w Jan 06 '17 at 19:38
8

Some key pertinent details about references and pointers

Pointers

  • Pointer variables are declared using the unary suffix declarator operator *
  • Pointer objects are assigned an address value, for example, by assignment to an array object, the address of an object using the & unary prefix operator, or assignment to the value of another pointer object
  • A pointer can be reassigned any number of times, pointing to different objects
  • A pointer is a variable that holds the assigned address. It takes up storage in memory equal to the size of the address for the target machine architecture
  • A pointer can be mathematically manipulated, for instance, by the increment or addition operators. Hence, one can iterate with a pointer, etc.
  • To get or set the contents of the object referred to by a pointer, one must use the unary prefix operator * to dereference it

References

  • References must be initialized when they are declared.
  • References are declared using the unary suffix declarator operator &.
  • When initializing a reference, one uses the name of the object to which they will refer directly, without the need for the unary prefix operator &
  • Once initialized, references cannot be pointed to something else by assignment or arithmetical manipulation
  • There is no need to dereference the reference to get or set the contents of the object it refers to
  • Assignment operations on the reference manipulate the contents of the object it points to (after initialization), not the reference itself (does not change where it points to)
  • Arithmetic operations on the reference manipulate the contents of the object it points to, not the reference itself (does not change where it points to)
  • In pretty much all implementations, the reference is actually stored as an address in memory of the referred to object. Hence, it takes up storage in memory equal to the size of the address for the target machine architecture just like a pointer object

Even though pointers and references are implemented in much the same way "under-the-hood," the compiler treats them differently, resulting in all the differences described above.

Article

A recent article I wrote that goes into much greater detail than I can show here and should be very helpful for this question, especially about how things happen in memory:

Arrays, Pointers and References Under the Hood In-Depth Article

Community
  • 1
  • 1
Xitalogy
  • 1,592
  • 1
  • 14
  • 17
  • 1
    I suggest adding the main points from the article to the answer itself. Link-only answers are usually discouraged, see https://stackoverflow.com/help/deleted-answers – HolyBlackCat Aug 01 '19 at 08:05
  • @HolyBlackCat I was wondering about that. The article is long and in-depth, and develops from first principles up to in-depth treatments with lots of code examples and memory dumps then finishes with exercises that further develop the in-depth code examples and explanations. It also has a lot of diagrams. I will try to figure out how to put some of the key points in here directly, but not sure right now how to do that in the best way. Thank you very much for your input. I will do my best before my answer gets deleted. – Xitalogy Aug 01 '19 at 08:18
8

Summary from answers and links below:

  1. A pointer can be re-assigned any number of times while a reference cannot be re-assigned after binding.
  2. Pointers can point nowhere (NULL), whereas a reference always refers to an object.
  3. You can't take the address of a reference like you can with pointers.
  4. There's no "reference arithmetic" (but you can take the address of an object pointed by a reference and do pointer arithmetic on it as in &obj + 5).

To clarify a misconception:

The C++ standard is very careful to avoid dictating how a compiler may implement references, but every C++ compiler implements references as pointers. That is, a declaration such as:

int &ri = i;

if it's not optimized away entirely, allocates the same amount of storage as a pointer, and places the address of i into that storage.

So, a pointer and a reference both use the same amount of memory.

As a general rule,

  • Use references in function parameters and return types to provide useful and self-documenting interfaces.
  • Use pointers for implementing algorithms and data structures.

Interesting read:

S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
8

in simple words, we can say a reference is an alternative name for a variable whereas, a pointer is a variable that holds the address of another variable. e.g.

int a = 20;
int &r = a;
r = 40;  /* now the value of a is changed to 40 */

int b =20;
int *ptr;
ptr = &b;  /*assigns address of b to ptr not the value */
Sadhana Singh
  • 197
  • 2
  • 4
  • 12
7

The difference is that non-constant pointer variable(not to be confused with a pointer to constant) may be changed at some time during program execution, requires pointer semantics to be used(&,*) operators, while references can be set upon initialization only(that's why you can set them in constructor initializer list only, but not somehow else) and use ordinary value accessing semantics. Basically references were introduced to allow support for operators overloading as I had read in some very old book. As somebody stated in this thread - pointer can be set to 0 or whatever value you want. 0(NULL, nullptr) means that the pointer is initialized with nothing. It is an error to dereference null pointer. But actually the pointer may contain a value that doesn't point to some correct memory location. References in their turn try not to allow a user to initialize a reference to something that cannot be referenced due to the fact that you always provide rvalue of correct type to it. Although there are a lot of ways to make reference variable be initialized to a wrong memory location - it is better for you not to dig this deep into details. On machine level both pointer and reference work uniformly - via pointers. Let's say in essential references are syntactic sugar. rvalue references are different to this - they are naturally stack/heap objects.

Zorgiev
  • 794
  • 1
  • 7
  • 19
4

I always decide by this rule from C++ Core Guidelines:

Prefer T* over T& when "no argument" is a valid option

Hitokage
  • 733
  • 8
  • 19
  • 1
    Using overloaded functions which do not take pointers instead of allowing `nullptr`, or using terminal objects, is arguable a much better solution, instead of allowing `nullptr` as arguments. – Clearer Dec 19 '17 at 09:01
  • 1
    @Clearer It is probably cleaner but sometimes you just need to quickly pass pointers around and there might be cases when you don't care if the pointer is null or not. – Hitokage Dec 19 '17 at 10:02
4

I have an analogy for references and pointers, think of references as another name for an object and pointers as the address of an object.

// receives an alias of an int, an address of an int and an int value
public void my_function(int& a,int* b,int c){
    int d = 1; // declares an integer named d
    int &e = d; // declares that e is an alias of d
    // using either d or e will yield the same result as d and e name the same object
    int *f = e; // invalid, you are trying to place an object in an address
    // imagine writting your name in an address field 
    int *g = f; // writes an address to an address
    g = &d; // &d means get me the address of the object named d you could also
    // use &e as it is an alias of d and write it on g, which is an address so it's ok
}
Immac
  • 466
  • 1
  • 5
  • 16
4

You can use the difference between references and pointers if you follow a convention for arguments passed to a function. Const references are for data passed into a function, and pointers are for data passed out of a function. In other languages, you can explicit notate this with keywords such as in and out. In C++, you can declare (by convention) the equivalent. For example,

void DoSomething(const Foo& thisIsAnInput, Foo* thisIsAnOutput)
{
   if (thisIsAnOuput)
      *thisIsAnOutput = thisIsAnInput;
}

The use of references as inputs and pointers as outputs is part of the Google style guide.

Mark Lakata
  • 19,989
  • 5
  • 106
  • 123
  • 3
    There's nothing inherently input-ish or output-ish about pointers versus references. The important difference is the presence or absence of a `const`. – Sneftel Aug 09 '18 at 15:55
  • 1
    I agree, there is nothing inherently input-ish or output-ish. What I was mentioning was just a convention (that I didn't invent). The convention is part of the [Google style guide](https://google.github.io/styleguide/cppguide.html#Output_Parameters). There is one advantage of pointers as output, and that they can be nullable if you don't want the output. – Mark Lakata Aug 10 '18 at 21:34
  • 2
    How is this different from my answer 8 months earlier? It even references the same style guide! – Arthur Tacca Oct 13 '18 at 10:32
4

Beside all the answers here,

you can implement operator overloading using references:

my_point operator+(const my_point& a, const my_point& b)
{
  return { a.x + b.x, a.y + b.y };
}

Using parameters as value would create temporary copies of the original arguments and using pointers would not invoke this function because of pointers arithmetics.

ebasconp
  • 1,608
  • 2
  • 17
  • 27
  • 3
    It isn't that it won't be called: you can't even **declare** such operator with two pointer parameters; according to the [draft std](http://eel.is/c++draft/over.oper#6) "_An operator function shall either be a non-static member function or be a non-member function that has **at least one parameter whose type is a class, a reference to a class, an enumeration, or a reference to an enumeration**._" ([over.oper]/6) – curiousguy Jan 30 '19 at 01:29
4

Think about a pointer as about a business card:

  • It gives you a chance to contact someone
  • It can be empy
  • It can contain wrong or outdated information
  • You are not sure someone, mentioned on it, is even still alive
  • You can't talk directly to the card, you only can use it to call someone
  • Maybe there are many such cards exist

Think about a reference as about an active call with someone:

  • You are pretty sure someone, you contacted, is alive
  • You can talk directly, no extra calls are needed
  • You are pretty sure you talk not to an empty place or a piece of garbage
  • You can't be sure you are the only one, who is currently talking with this object
Ezh
  • 579
  • 1
  • 7
  • 26
  • Yeah, the reference is obliged to go out of scope before the original variable (i..e the reference is on top of the original variable in the stack). – Maf Mar 29 '23 at 22:08
3

Taryn♦ said:

You can't take the address of a reference like you can with pointers.

Actually you can.

I'm quoting from an answer on another question:

The C++ FAQ says it best:

Unlike a pointer, once a reference is bound to an object, it can not be "reseated" to another object. The reference itself isn't an object (it has no identity; taking the address of a reference gives you the address of the referent; remember: the reference is its referent).

Pang
  • 9,564
  • 146
  • 81
  • 122
3

A pointer is a variable that holds the memory address of another variable , where as a reference is an alias to an existing variable. (another name of the already existing variable)

1. A pointer can be initialised as:

int b = 15;
int *q = &b;

OR

int *q;
q = &b;

where as reference,

int b=15;
int &c=b;

(declare and initialize in a single step)

  1. A pointer can be assigned to null, but reference cannot
  2. Various arithmetic operations can be performed on pointers whereas there is no such thing called Reference Arithmetic.
  3. A pointer can be reassigned , but reference cannot
  4. A pointer has its own memory address and size on the stack whereas a reference shares the same memory address
  • A reference is not always an alias for an existing variable. References can extend the lifetime of temporary objects. – einpoklum Nov 10 '21 at 23:38
1

"I know references are syntactic sugar, so code is easier to read and write"

This. A reference is not another way to implement a pointer, although it covers a huge pointer use case. A pointer is a datatype -- an address that in general points to a actual value. However it can be set to zero, or a couple of places after the address using address arithmetic, etc. A reference is 'syntactic sugar' for a variable which has its own value.

C only had pass by value semantics. Getting the address of the data a variable was referring to and sending that to a function was a way to pass by 'reference'. A reference shortcuts this semantically by 'referring' to the original data location itself. So:

int x = 1;
int *y = &x;
int &z = x;

Y is an int pointer, pointing to the location where x is stored. X and Z refer to the same storage place (the stack or the heap).

Alot of people have talked about the difference between the two (pointers and references) as if they are the same thing with different usages. They are not the same at all.

1) "A pointer can be re-assigned any number of times while a reference cannot be re-assigned after binding." -- a pointer is an address data type which points to data. A reference is another name for the data. So you can 'reassign' a reference. You just can't reassign the data location it refers to. Just like you can't change the data location that 'x' refers to, you can't do that to 'z'.

x = 2;
*y = 2;
z = 2;

The same. It is a reassignment.

2) "Pointers can point nowhere (NULL), whereas a reference always refers to an object" -- again with the confusion. The reference is just another name for the object. A null pointer means (semantically) that it isn't referring to anything, whereas the reference was created by saying it was another name for 'x'. Since

3) "You can't take the address of a reference like you can with pointers" -- Yes you can. Again with the confusion. If you are trying to find the address of the pointer that is being used as a reference, that is a problem -- cause references are not pointers to the object. They are the object. So you can get the address of the object, and you can get the address of the pointer. Cause they are both getting the address of data (one the object's location in memory, the other the pointer to the objects location in memory).

int *yz = &z; -- legal
int **yy = &y; -- legal

int *yx = &x; -- legal; notice how this looks like the z example.  x and z are equivalent.

4) "There's no "reference arithmetic"" -- again with the confusion -- since the example above has z being a reference to x and both are therefore integers, 'reference' arithmetic means for example adding 1 to the value referred to by x.

x++;
z++;

*y++;  // what people assume is happening behind the scenes, but isn't. it would produce the same results in this example.
*(y++);  // this one adds to the pointer, and then dereferences it.  It makes sense that a pointer datatype (an address) can be incremented.  Just like an int can be incremented. 
Gerard ONeill
  • 3,914
  • 39
  • 25
1

Basic meaning of pointer(*) is "Value at address of" which means whatever address you provide it will give value at that address. Once you change the address it will give the new value, while reference variable used to reference any particular variable and which can't be change to reference any other variable in future.

-1

you can not dereference a reference like a pointer, which when dereferenced gives values at that location,

both reference and pointer work by the address though...

so

you can do this

int* val = 0xDEADBEEF; *val is something at 0xDEADBEEF.

you can not do this int& val = 1;

*val is not allowed.

-1

lots of valuable info above, but my advice to novice c++ programmers.

Avoid pointers, use them only where you have no other choice (because you're interfacing with a library that only accepts a pointer). I know a lot of books and tutorials do so, but asking a novice to write code to manipulate raw pointers is not a good way to introduce a new programmer to the language.

If you don't need to be able to change to what object is being pointed, use a reference. If you do need to change what's pointed to, use a smart pointer.

while 'technically' you can construct a reference that points to bogus data, this requires you to have already done some bad pointer manipulation, or you passed something by reference that isn't immediately used, but stored and used later when the object was already destroyed. It is perfectly acceptable (and good form) to assume a reference points to a validly constructed object. You shouldn't write a bunch of code to test if a reference is pointing to a valid object.

Pointers have the added complexity of "points to nothing" (NULL, or nullptr) which you may have to check for. Pointers add the complexity of "who (and how) is responsible of cleaning up the data the pointer points to".

oreubens
  • 329
  • 1
  • 9