4

OK, I'm facing this all the time in many functions I write, which should I use?

void sth(int* a)
void sth(int& a)

Which one is faster, regarding two separate occasions: a is a small variable or a is a large data struct.

I would like a deep answers with pertinence to the actual hardware and stack process.

  • 2
    int& doesn't exist in C. – mouviciel Oct 20 '13 at 12:56
  • Is there seriously no int& in C? How is that possible, & and * are very closely linked to each other. Although, this statement does explain my observation why so many codes (cpp and c) use * over & in arguments. Frankly, Ive only seen & a couple of times. – user209347 Oct 22 '13 at 19:57
  • 2
    int& has nothing to do with pointers. int& is a reference to an int, and C does not have reference types. – bstamour Oct 24 '13 at 13:15
  • 2
    You asked for pertinence to the actual hardware, but don't mention what actual hardware you're interested in. Any specific platform? – Useless Oct 24 '13 at 13:21
  • 1
    int& just offers a measure of safety over int*, and improves readability slightly by making the intent more obviously. There's nothing you can do with int& that you can't do with int*. That's how C gets away with not having it. – Steven Burnap Oct 24 '13 at 20:37
12

Most compilers will implement references as pointers. So the deep answer to your question is that there will be absolutely no difference in terms of performance between the two. (Doesn't change aliasing analysis either as far as I know.)

If you want to be 100% sure of that statement, inspect your compiler's output.

struct Small {
    int s;
};
void foo(Small* s)
{
    s->s = 1;
}
void bar(Small& s)
{
    s.s = 1;
}

Compiled with clang++ -O2, saving the assembly:

_Z3fooP5Small:                          # @_Z3fooP5Small
    .cfi_startproc
# BB#0:
    movl    $1, (%rdi)
    ret
_Z3barR5Small:                          # @_Z3barR5Small
    .cfi_startproc
# BB#0:
    movl    $1, (%rdi)
    ret

You can try that with a large struct or an enormously complex struct - doesn't matter, all you're passing in to the function is a pointer.

That being said, there are semantic differences between the two. The most important one being that, as long as your program is free of undefined behavior, the overload that takes a reference is guaranteed to get a reference to a valid, live object. The pointer overload isn't.

Also assigning to s in these two examples has completely different meanings. It would replace the pointer in the first function (i.e. whatever it pointed to remains unchanged, but becomes unreachable from within that function; caller unaffected by the assignment).
In the second, it would call the appropriate assignment operator en the object passed in (effect visible from the caller).

So your choice shouldn't be made on a potential performance difference (there will generally be none), but on semantics. What you need the function to be able to do, and how you should be able to call it, will dictate what overload(s) you need to provide.

  • This answer is very intriguing, especially because you show the low level assembly to substantiate your point! I like that! Basically, using pointers/references won't matter according to you guys, and since reference is safer (and easier, syntax in function is like direct access), ill more likely use those. – user209347 Oct 22 '13 at 19:54
  • However, one question, why do so many codes I have seen use pointers over references in arguments? Most functions I see use int sth(sth* sth) instead of &. And I read that when passing large structs, a pointer/reference is faster than just copying the value into your arguments stack, is that true? – user209347 Oct 22 '13 at 19:55
  • 1
    The fact that you can't pass a null (no object) with a reference parameter can be a reason to use a pointer instead. Passing ownership of something also requires pointers. Interactions/interfaces with C can't use references. And the semantics, as I said, are different. As for copy vs pointer/reference - it depends. You need to benchmark. Optimizers have an easier time when you pass values around. – Mat Oct 23 '13 at 3:49
  • 1
    References were also not an original feature of C++ so some code uses pointers simply because the feature didn't exist when the code was written, or the code was written by older programmers used to using pointers. – Steven Burnap Oct 24 '13 at 20:33
10

The main semantic differerence between int* and int& is that the former allows passing of NULL or uninitialized values, and the latter does not. So the implementation of a function using pointers should look like this:

 void sth(int* a)
 {
     if(a==NULL)
     {
         // handle NULL case
     }
     else
     {
         // do something with *a
     }
 }

When using references, you can omit that special NULL handling within the function.

So if the function you are going to write does not explicitly has a special need to allow NULL values as input, use int&. See also this Wikipedia entry.

Note that you should not make your decision based on which of the 2 alternatives is faster. Your first priority should be correct code, not any micro-optimizations, which I would expect in this case to be neglectable.

  • You have to put more effort to pass a NULL (or an uninitialized pointer) for an înt& parameter, but you can do it using * ((int *) 0). – Giorgio Oct 20 '13 at 12:10
  • 7
    @Giorgio: using references instead of pointers makes unintentional errors unlikely, but if you want to bypass this intentionally, in C++ there are of course always ways to achieve this. – Doc Brown Oct 20 '13 at 15:22
  • 1
    Gonna cover/recommend the use of const int&, and mention rvalues? And while you're there you could mention right to left reading order (int const&) :-) – Grimm The Opiner Oct 21 '13 at 10:40
  • @DocBrown Pointers are part of the language and there is functions returning pointers. So writing sth(*a) is legitim, common, code. – Michael Le Barbier Grünewald Oct 24 '13 at 13:53
  • @michipili: I don't understand what you are trying to tell me, but my answer is not about syntactically correctness, it's about how to make errors more unlikely. – Doc Brown Nov 2 '13 at 20:13
4

The most important difference between references and pointers is that you cannot free an object through a reference while it is possible to do it through a pointer.

Thus, selecting the reference type instead of the pointer type for an argument a in a method of an object b advertises that ownership of a is not transferred to b.

(The common belief, that it is not possible to pass a dereferenced NULL as a reference to a method without cheating is wrong. Most methods creating an object —e.g. clone or factories—will return a pointer, NULL or not. If the method you want to call with the freshly created object uses references, you have to dereference the pointer.)

1

Reference and Pointers are two implementation of a same concept: indirection (that is "talk about something through a pronoun")

At machine level they are the same thing (index of a memory cell), so there in no performance distinction. At language level the main difference is mostly in being "explicit" and "mutable":

  • pointer dereferencing is explicit: given pa = &a; a.x is the same of pa->x
  • reference dereferencing is implicit: given ra = a; a.x is the same as ra.x

The identical syntax inside expressions makes reference more suitable in generic functions, since the way they will be expressed won't change whether the access to the variable is direct or indirect.

  • pointer are mutable: pa = &a1; ...; pa = &a2; or ++pa or pa[x] are all possible
  • reference are unmutable: ra = a1; ... ; ra= a2; in fact assign the a2 value to a1 (thus playing a different game)

The mutable nature of pointers make them more suitable implementing generic iterators.

It is like talking about fixed versus adaptive wrenches. Their different shape makes their usability to change respect to certain context. But for the screw standpoint, they are just wrenches.

-1

References are converted to pointers by the compiler so at run time there is no difference in speed. Speed is not the reason you choose references instead of pointers but in fact references might be a bit faster in your overall code simply because you don't need to constantly check for invalid references (NULL pointers).

If a is a small variable (no larger than the machine address size), then there is no difference between a and &a. If a is larger than the machine's address size (e.g. a class object) then &a is faster and &a must be done (rather than a).

Of course you need to consider whether you want to be able to edit a in the called function. If a is large and you want to forbid changing of a, pass a constant reference to a.

If using C++, you should always use references when possible. A good C++ book will list what the difference between references and pointers are. You should consider the following:

References are implemented underneath as pointers. So why use a reference? Because it allows the function writer to determine how a function works without affecting how it is called. With references, the caller of a function doesn't need to know if the function takes a pointer or the object itself. For example, you call the following 2 functions the same way and notice that we can change add1 to use references without affecting all the callers:

int add1 (int a, int b);
int add2 (int &a, int &b) {
// this actually gets converted by the compiler to
// *a + *b
    return a + b;
}

If you were using pointers, you'd have to know that the function is actually taking the address, not the object itself. In other words, references add to information hiding.

So to sum up, references are just syntactic sugar. The compiler will convert all references to pointers and operation to references to valid operations with/on pointers.

Second, unlike pointers - a reference is the object. With pointers, you can change the object pointed to or you can change the pointer itself (in which case it will point to something else). With a reference there's only one thing you can change - the referred object.

Third, references cannot be re-assigned to refer to another object like a pointer can. Often, in linked lists you have to move pointers forward/backwards. You can't do this with a reference. Think of a reference as an alias to an object.

Lastly, about the NULL...in C code you will see a lot of NULL pointer checking. References are meant to help with that by allowing the compiler to catch whenever a reference doesn't refer to a valid object. The C++ standard also says that a reference cannot point to an invalid object (e.g. a NULL). However, I think it's up to the compiler on how it implements that so you need to double check with your compiler. I think some compilers will not even warn you.

  • 1
    The answer is inconsistent. If references are implemented underneath as pointers, how can pointers be faster than references. – Bart van Ingen Schenau Oct 20 '13 at 10:33
  • I meant &a vs just a at the beginning. I've corrected it. – s5s Oct 20 '13 at 10:57
  • 1
    I still find that paragraph confusing and it does not seem to add any value to your answer. I would remove it if I were you. – Bart van Ingen Schenau Oct 20 '13 at 13:07
  • 1
    There is nowhere in the C++ standard that says references have to be implemented as pointers. However it does explicitly state that whether or not references even require storage at all is an implementation detail. – bstamour Oct 21 '13 at 15:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.