72

Are these the same:

int foo(bar* p) {
  return p->someInt();
}

and

int foo(bar& r) {
  return r.someInt();
}

Ignore the null pointer potential. Are these two functions functionally identical no matter if someInt() is virtual or if they are passed a bar or a subclass of bar?

Does this slice anything:

bar& ref = *ptr_to_bar;
Artjom B.
  • 61,146
  • 24
  • 125
  • 222
criddell
  • 14,289
  • 9
  • 41
  • 45

8 Answers8

79

C++ references are intentionally not specified in the standard to be implemented using pointers. A reference is more like a "synonym" to a variable than a pointer to it. This semantics opens some possible optimizations for the compiler when it's possible to realize that a pointer would be an overkill in some situations.

A few more differences:

  • You can't assign NULL to a reference. This is a crucial difference and the main reason you'd prefer one over the other.
  • When you take the address of a pointer, you get the address of the pointer variable. When you take the address of a reference, you get the address of the variable being referred to.
  • You can't reassign a reference. Once it is initialized it points to the same object for its entire life.
Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
shoosh
  • 76,898
  • 55
  • 205
  • 325
  • 6
    You actually can assign NULL to a reference IF you cast it to a pointer of the type and then dereference the point e.g. int &ref = *(int*)NULL; and you can also reassign a reference if you place it within a union and change the corresponding value in the union. – Grant Peters Mar 07 '09 at 03:29
  • 1
    And i should add that these should never be done because when a function asks for a reference, it doesn't ever expect NULL, and although most references are basically implemented the same way as pointers, this MAY not be the case in all scenarios/platforms. – Grant Peters Mar 07 '09 at 03:31
  • 2
    if you're assigning to a corresponding value of a union then you're not really assigning to a reference are you? – shoosh Mar 07 '09 at 11:08
  • It is helpful to clarify that assigning a non-const reference to a const value (similarly to NULL as it is a const, macro defined value) is not "possible". While it is technically possible to do these sorts of manipulations with low-level manipulation, it should not be done in production code. C++11 is helpful with the introduction of nullptr as a type and the encouragement of its universal adoption. – Dr.Ransom Aug 14 '20 at 22:34
15

Ignoring every syntactic sugar and possibilities that can be done with the one and not with the other and difference between pointers and references explained in other answers (to other questions) ... Yeah those two are functionally exactly the same! Both call the function and both handle virtual functions equally well.

And no, your line does not slice. It's just binding the reference directly to the object pointed to by a pointer.

Some questions on why you would want to use one over the other:

Instead of trying to come up with differences myself, i delegate you to those in case you want to know.

Community
  • 1
  • 1
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
13

Reference is a constant pointer i.e., you can't change the reference to refer to other object. If you change, value of the referring object changes.

For Ex:

       int j = 10;
       int &i = j;
       int l = 20;
       i = l; // Now value of j = 20

       int *k = &j;
       k = &l;   // Value of j is still 10
Vinay
  • 4,743
  • 7
  • 33
  • 43
8

Yes they are functionally identical. Since a reference will require you to set it to an object before using it, you wont have to deal with null-pointers or pointers to invalid memory.

It is also important to see the semantical difference:

  • Use a reference when you would actually pass the object normal - but it is so large that it makes more sense to pass a reference to the object rather than making a copy (if you are not modifying the object that is).
  • Use a pointer when you want to deal with the memory address rather than with the object.
Patrick Glandien
  • 7,791
  • 5
  • 41
  • 47
6

I haven't used C++ in a long time, so I'm not even going to attempt to really answer your question (sorry); However, Eric Lippert just posted an excellent article about pointers/references that I figured I'd point you to.

Chris Shaffer
  • 32,199
  • 5
  • 49
  • 61
4

Not sure if anyone answered your 2nd question hidden at the bottom about slicing... no that won't cause slicing.

Slicing is when a derived object is assigned (copied) to a base class object -- the derived class's specialization is "sliced" off. Note that I said the object is copied, we're not talking about pointers being copied/assigned, but the objects themselves.

In your example, that's not happening. You're just de-referencing a pointer to a Bar object (thereby resulting in a Bar object) being used as the rvalue in a reference initialization. Not sure I got my terminology right...

Dan
  • 10,303
  • 5
  • 36
  • 53
3

As everyone else has mentioned, in implementation references and pointers are largely the same. There are some minor caveats:

  • You can't assign NULL to a reference (shoosh mentioned this): that's significant since there is no "undefined" or "invalid" reference value.

  • You can pass a temporary variable as a const reference, but it's not legal to pass a pointer to a temporary.

For example, this is okay:

class Thingy; // assume a constructor Thingy(int,int)
void foo(const Thingy &a)
{ 
   a.DoSomething();
}

void bar( ) 
{
  foo( Thingy(1,2) );
}

but most compilers will complain about

void foo2( Thingy * a);

void bar2()
{
  foo( &Thingy(1,2) );
}
  • Taking the address of a variable to get a pointer forces the compiler to save it to memory. Assigning a reference to a local variable just creates a synonym; in some cases this may allow the compiler to keep the data on the register and avoid a load-hit-store. However, this only applies to local variables -- once something is passed as a parameter by reference, there's no avoiding saving it to stack.

 

void foo()
{
   int a = 5;
   // this may be slightly more efficient
   int &b = a;
   printf( "%d", ++b );
   // than this
   int *c = &a;
   printf( "%d", ++(*c) );
}
  • Similarly, the __restrict keyword cannot be applied to references, only pointers.

  • You can't do pointer arithmetic with references, so whereas if you have a pointer into an array then the next element in the array can be had through p+1, a reference only ever points at one thing in its entire life.

Crashworks
  • 40,496
  • 12
  • 101
  • 170
1

The functions are obviously not "the same", but with regard to virtual behaviour they will behave similarly. Regarding slicing, this only happens when you deal withvalues, not references or pointers.